Three.js Shaders (GLSL) Crash Course For Absolute Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys in this video we're going to explore the basics of writing shaders in jlsl so first we're going to see what shaders are how to set them up in 3js how to write jlsl and then we're going to go through a series of different exercises to create different shapes and patterns and finally we're going to create a project and I'm going to show you the full process of writing a Shader from scratch going from zero to something that looks good so what are shaders and why do we need them well in 3D Graphics the main thing that we want to do is rendering objects now I might want to render this Rubik's Cube here or I might want to render a simple sphere and okay we want to render the sphere we want to draw the sphere and we need to tell the GPU to somehow draw the sphere for us as you know uh the GPU only can draw triangles so let's draw a triangle here and okay we want to draw this triangle with the help of the GPU and we need to tell the GPU how to actually draw this so the only pieces of information that the GPU needs is the positions of these vertices so I'm going to write positions here and the other piece of information that our GPU needs is the color of this triangle and that's essentially what the vertex and the fragment Shader do now um the vertex here tells our GPU where uh these vertices are placed so I'm going to write vertex Shader here and the fragment share tells our GPU how to actually fill this triangle with a color and okay that's the basics of what the vertex and the fragments here do now why do we even need to tell the GPU to draw these triangles for us why not tell the CPU well the structure of a CPU is a bit different you see I have a CPU with eight cores and eight threads now if I want to run multiple tasks at the same time I can use those eight Frets to run multiple tasks at the same time now the difference is the GPU has hundreds of threads so the GPU can run hundreds of different tasks at the same time and okay we understand that the vertex here tells our GPU where our vertices are placed but what is it and how does it really work well a Vertex Trader is a program that runs for every single vertex so we have a programming language for this called jlsl we write this program that is called the vertex here and this program runs for every single vertex for our object and the interesting thing is these vertices have no idea what positions other vertices have and as I said the GPU runs this vertex here in parallel for every single vertex and okay now what does the fragment share do well the fragmenter is very similar but the fragments here runs for every single Pixel in our triangle and again these pixels have no idea what the color of their neighbor pixel is um they just don't have any shared data so you can imagine that the fragment share runs for every single Pixel and tries to fill the color of our triangle right so that's the basics of what you need to know about a Vertex here and a fragment chair and okay there are a couple of details about how does the vertex Shader work with the fragment trigger but we're going to get into that later so let's see how we can set up a fragment share and a Vertex Shader in 3js and here inside the vs code I have this Reaper opened which you can download from a link in the description and the first you need to npm install to install the modules um needed to run this now um in the terminal you need to run npm run start to run this and when you run it you'll get this um which is a sphere with some lighting now uh if I go back to vs code if I open up the SRC folder app.js is where the main stuff happens so let's open that up and here uh at the top we have some code which is unimportant and here I've isolated uh the code that is actually important now if you're a beginner in 3GS and you know nothing about 3GS I recommend you watch a video um that I've Linked In the description for you so um with that being said we have the main section of this whole thing here we create an icocetron geometry we create image standard material we create a mesh from those and we add that mesh to the scene and we will get this a white icosphere so the first thing that I want to change is this mesh standard material so let's do Shader material um and when you do that you'll get this red icosphere now that's already working with shaders you're already working with chairs it's just that you haven't provided them to this share material and the straighter material class is actually using some default shaders so those shares those default shaders can actually be a good starting point so let's close this SRC folder let's hop into node modules let's scroll down to find three so uh here it is and in the SRC folder um scroll down you're gonna see materials click on that and uh here down down in the materials folder you'll see share material.js so open that up and here you're going to see the class of sugar material and you can see the code behind that class now if we scroll down a bit you're gonna see this piece of code in the Constructor we have a default vertex and a default fragmenter and here you can do control click to open it up so here you're going to see the Shader code and uh this might look a bit different for you uh here we're using this comment actually 3GS is using this comment and uh we're using an extension called jlsl literal so uh you can download that and install it for vs code same tag styling for jealousel inside of JavaScript tag template strings so that's what it does and with that yeah you will get this syntax highlighting with within vs code now this is the JS file of course and we're exporting this string so already you can see that shaders are strings and then we compile these strings which are written in jlsl and uh that's that's how shares work now let's open up default.fragment2 and you can see we have the frame interior exact same stuff uh of course the code is different now what we want to do is we want to copy these into some jlsl files right so uh let's copy this bit of code here in the vertex Shader let's go into app.js and if you scroll up at the top I've put some vertex share and fragment share files for you and I've already placed those in the shaders folder um in the SRC folder of our repo so if you open that up control click um here Ctrl click uh that's going to open that up um and here you can paste uh what you just copied uh from the 3Gs uh JS file so we're going to do the same thing for the fragmenter uh come here just copy it and um in the Prime Minister control click and paste that in so that's all uh you can see these are jlsl files and the way that this handle is uh we're using the raw loader and uh what the raw loader does is it's it's essentially taking these files and turning them into text and strings so we're going to come down here in the share material section we're gonna pass down an object and we're gonna do vertex Shader equals vertex here same thing for the fragment shooter I mean sure equals fragmenter and you're gonna see the exact same thing because uh we just copied some codes from 3GS that is there by default but if we if we go into this fragment.jlsl which is where the color of our object is defined you can see we get we have this uh Vic 4 construct and what is what it's doing essentially is uh this is the red Channel this is the green Channel this is the blue Channel and this is the alpha channel so you can see we have the red at one and the blue and green are at zero and we get red of course let's change this to zero let's um change the green to one and as you can see here we get green right it makes sense so that's all the setup that you need to do in order to run your shaders with 3GS and now I'm going to explain jlsl here in the fragment shooter because it's very easy to visualize things in the fragment here all right so let's close this and this and this uh we don't need them anymore let's also close this uh let's zoom in a bit so um let's let's see what's going on in this fragment here um so first uh we see void and we see something that looks like a function definition and uh we're setting this variable uh to something um all right that that's what we understand um if you have a basic understanding of programming languages now um right off the bat you see this void here so jealousel is a typed language and uh if you want to see common types that are used in different programming languages I'll put a link in the description in case you're interested in that but here we have a few different types available to us so we can do float we can do double we can do ins uh we can use um I don't know U and things like that right but jlsl has some unique types too so if I come down here I can use vect3 what does that mean here well if you if you've used um three just Vector three it's kind of similar um what this does is this holds an X and A Y and a z so that's what it does uh this is by the way not a syntax um card syntax I need to comment these um so uh fx3 holds an X Y and Z we also have a vic2 which holds an X Y so you start to understand what's happening but what are these X and Y values well when you use a vic2 or a vect3 or a vac-4 which are available Vex 5 is not available when you use those um you're actually storing floats okay so you're storing floating points um in in these constructs now uh if I comment these I can come down here and I can do ivic 3. uh if you want to hold X Y and Z but you want them to be an end you use ivac 3. uvex3 also exists um you also have Boolean up there full uh you can see um it's getting highlighted um you also have bevik 2 for example and so on uh so you can have also Divac 2 dvx3 Double um and yeah these are all things you could use in jlsl so these are the types that yellow cell has by default now okay that's cool um but how do we actually Define a variable in gel a cell well let's come down here and what's Happening Here is we are setting this variable to Avec 4. um so these are all floating points and um here if we want to take this we can do vac 4 um I don't know color equals this put a semicolon there now uh we're setting this color to this effect four um and you need to specify the type at the beginning and the variable name and here we can set this variable again to color that works and we get our green sphere so uh that's very simple stuff that you can do now let me show you one thing you can do with these Constructors um so I have this Effect 4 Constructor which takes four floats now the cool thing is that I can pass only one float so if I do one here um um what what happens here is we get white and that's because for every single uh component x y z w that's the fourth component uh it's setting all of those to one right so uh that's one thing you could do another thing you could do is use a vic2 for the X Y like you can do vect two one and one and you can also do back two one and one that also works uh and you can see we get our white sphere right so uh you can do two Vic twos and what this represents is two xy's um which will be the X Y of this and uh the other two components here will Define the Z and the W all right you can also dovex3 and put the one here and um you can also do a single one right so because this is a vic3 it holds three components um we need Vic four we need to add one more component here at the end which is a floating points so um you can do all of that that works um if I make a mistake here for example if I remove the semicolon uh we'll get an error because shares uh gets compiled if I go into my console uh if I zoom this in you can see we get our error it's saying syntax server all right so um this gets compiled and if I make a mistake uh this doesn't compile actually so so that's all very simple let's set this to Green again so put this at zero and put this as zero and you'll get green again right so so now you know how to work with these types how to create a variable and you can also do float uh green value for example I'm just sharing this as an example and come here and say green value right that works now one thing that you might have realized is that if I come here and create a vector call it my vector equals uh and use of x3 Constructor if I use an INT here uh this is fine this works right um the reason for that is this Constructor considers Institute so it takes into account that this is an INT converts it into a float and it says all of those components x y z to one and I can prove this and here I can do Vector my vector dot x uh set the x value of this Vector to zero this is an INT this is not a float and this gives me an error why because I haven't converted um my zero to a float the way I would do that is I put a dot here um that works it's the same as essentially a DOT zero I can remove the zero this also works right so here I'm trying to explain uh different things all at once now the other thing is um I think you can also do F here if you want to zero dot f means float uh that compiles fine um I can do one here and so on right so this f means I'm converting your uh number here to a float um and that all works fine now here's the thing that you can do in jlsl um for example in JavaScript you have classes um in general cell you have structs so I can do struct and I can call my struct I don't know vic5 because why not uh jealous it doesn't provide that now it's important to put a semicolon here after the curly brackets and here I can specify my components of the struct so I can do float X [Music] float y float Z float w and finally float Cube and the way that this would work is I can come down here and do um vect five my vector and what I can do is I can do equals like five which is a Constructor and I can give it this time I can't just give it an hint um because that's not a native uh struct in yellow cell I need to provide all the components so if I do one one one one one give us five components this is not going to work because I need to convert all of these to floats um so and if I do that that works that compiles fine uh so that's how that works um you can Define functions uh so the same way that we have this main function we can Define our own functions so we can do void do do nothing um and this is the way that we Define a function it returns nothing it takes nothing uh let's change that let's change that to sum let's do float and here I can take float a float B and return a plus b and this is a compiling fine and finally here I can do instead of the screen value I can do sum of 0.5 and 0.5 and this should work the exact same way as before so here I want to explain Swizzle masks and the name is a bit weird but uh the concept is very simple so here uh in the main function I'm going to define a vector so vic3 um and we're gonna get my Vector equals Vector three one zero one and if I call this color um I can also call this color so we can put the Vic 3 here as I just showed you um you can do a vic3 and with one with the Vic 4 Constructor this is gonna give us a Vic 4. so um this will give us purple I believe yep so uh now we want to set this color dot X to Zero remember if we do an end um it doesn't work it gives you an error because we need to convert this into a float now this is one way of converting things to a float either putting a DOT and f after that or putting it out and it's zero the other way is taking the ends and wrapping it like this around this float Constructor and this also casts it to float right I don't really use this that much um I just rather use the simple 0.0 okay that gives us blue because we're setting the color here to the red color here to zero now um the thing is we're we're modifying the X but in jlsl x y z w are the same as RGB a right so I can do R here also representing the red and it works um so color dot x equals dot zero these two lines are the same right because rgba is the same as X Y Z now I want to explain Swizzle masks so what are series of masks um and how can we use them well what if I wanted to modify or and G at the same time so in order to do that you might do something like RG you know put this as one or something you could do that but yellow cell gives you a convenient way to do this you can do RG so if you do RG you need to provide a vac 2 here remember you need to provide two floats because uh this is two components and uh here we can do for example I don't know whatever the vector Constructor allows um I can do zero one so what that does is uh this puts the or at zero and uh this will make the green value one so this gives us cyan color because the green and the blue are one uh let's change this to purple again so you can do that if you really want to now um the thing here is that you don't need to do this in order you can do G or green red this also works so we just reverse this and this you can also do grb that also works but here you need to provide a vek3 now so you can do do it like this and this should give you a green value because you're setting the green to One the red and the blue to zero so this gives you a green value all right so uh we understand that and this is the exact same thing as y um I don't know X Z and here's the thing though um so the thing that you need to be careful about is that you can't do x r that that doesn't work or XR I don't know G you know you can't use x y z with RGB that that doesn't work right so you can either do x y z or RGB together so that's a swizzle mask now uh if we remove this you can see we have this color um and this is supposed to give us a purple color now uh here I can use the Swizzle mask this time like this I can do x x x and what this gives us is this gives us a Vic 3 right so I have a vect3 here and a float which is a Vic four and this will give us white why because well the red value here is set to one so we're essentially what this means here uh is that we're doing this one one one and this gives us a white color right so uh you can use suzel mask like this you can do XX I don't know why at the end and this gives you a yellow color so there you go that's essentially what Swizzle masks are they're very useful um I don't know any other language that is capable of doing um Swizzle masks and now let's talk about some basic operators that you could use um we already saw the equals operator you can also do color.vec3 that's also possible so you saw this uh one other thing we could do is we could use the plus equals operator so if I set this to zero set this to zero and if I put I don't know 0 0 1 here uh this should give us blue and if I remove this um this will give us blue so you can do plus equals you can do minus equals you can do multiply equals and uh that does work but here we're multiplying everything by zero so it doesn't show us anything if I turn this to one this will give us something there we go and the other thing we could do is um divide equals that's also available so you have all these operators you can do week three I don't know my vector and color uh divided by Vic you know color dot x x divided by Vex Vic 2 because we're getting two components and we can do two and two here um we need to change this to effect two uh this will work it will compile fine so you can do all sorts of crazy things with jlsl now one thing you cannot do is you cannot do color.r um mod the mod operator um um doesn't exist in jlsl so uh the way that we you would do mod in general cell is using the mod function all right so uh we're gonna get into functions on how to use them next uh but for now we're going to delete that so if you do I don't know color dot X um you know mod equals or even uh mod alone let's create a new floats new floats uh equals this [Music] um uh for example if you do two this doesn't work this doesn't work because uh we don't have mod in jello so and here you can see mods Brown govern types no operation mod exists that takes left hand blah blah blah right so this doesn't exist but we could do mod color.x 2 we could that so if we take a look um let's see what's what's the problem I think I need to provide a float here uh for to take that yeah so uh mod works like this all right so now let's talk about uh the different math functions that are available like mod in jlsl because Jello cell has a lot of math functions that are very useful so variant just cover the basic ones here and uh some of some of the functions in jlsl we're gonna cover later in this video but I'm just going to cover the basic ones so you can use apps uh what that gives you is the absolute value of a number um so you can zoom in you can do Max these are all um valid functions in glsl you provide two functions you provide two values to these and the Min gives you the minimum value between those um and the max gives you the maximum value out of those two values so basic functions here uh what else you have mod which I just talked about you have sine you have cosine um you also have a 10 I think let's check that out yep you have that you have A10 and things like that you have all sorts of math functions that you could use now these are some of the basic ones um what else do we have we have the dot product we have the cross product uh these are both functions that you could use so uh yeah we have many of these and we will use these functions um in the future one interesting function that I pretty much always use in all of my projects is the clamp function this is a very important uh the clamp function what it does is you give it a number for example I give it um minus 0.1 I don't know and uh you can clamp it to fit a certain range so if the number goes below this Min value uh it gets it gets converted to the Min value so here this is minus 0.1 this will get converted to zero now if you go above one for example here which is the maximum value if you go above one put two here this will again be one but if you go in between this will return the value itself so this is a very useful function that we're going to work with later and you have also some uh some math functions that you might not be familiar with but these are super important so you have step you have smooth step uh yeah fract um and so on and we're going to cover these later I'm not going to tell you what they do now uh we're going to cover these later um down the line now a very interesting function that I found out about recently was this uh equal function so here uh you can do whatever you want with your types but for example if we go for a vac 3 we can do bvex3 and say okay is equal and uh we need to now do equal and we can provide two Vic threes here so this checks if two week threes are equal and it will check those components individually and it will return a b vac three so I can provide a vect3 here one with one um one with zero and all the all the numbers here should be uh all the booleans here in this B vac 3 should be false right because these are these two vectories are not equal in in any component so if I come here and say is equal if we try to visualize this remember booleans can only be true or false so this is all false and false um in this programming language is like many other languages zero so if we now take a look we're gonna get a black screen uh we don't get any error but this is this is a black now if I change this to one uh you will see this will be equal um and we will get white right and uh you know take a look at this Constructor this is avec4 um and uh it takes a b vac 3 here uh and it turns it into effect three um or essentially it takes all the components and turns it into floats and uh this will provide the full vect4 like this so that's very interesting um some of these things you cannot really do in other programming languages so yellow soul is really fun to work with and uh that's the basics of what you need to know from jail LaSalle as I said there are some functions that are very useful which you can use um and we're going to talk about those later in this video but for now that's all that you need to know about glsl all right so now let's delete all of this code um so we're gonna literally this we're gonna delete all of this code and you can see the fragment here is a very simple program and we can Define everything with just three lines of code so let's turn this back to red and uh if we do that we get our wrist sphere so that's all nice but um okay we We Now understand how the frame interior works we have this main function and we set this uh Global variable GL freck color which determines the fragments color um to red and we get red that that all makes sense um but now how does the vertex Shader work so let's take a look at the vertex here if I click here you're gonna see again uh we get three lines of code very simple but um here again okay we have void main um that makes sense we have the GL position which defines the position of the vertices as we discussed that also makes sense and this is a global variable again that also makes sense but here we have three different keywords that we have no idea uh what they are so we have projection Matrix multiplied by model view Matrix and we have this position keyword and you don't see the definition of these uh here in this file and that's because uh three gesture material class uh already creates these for you so in order for me to explain what's Happening Here we need to take a step back and we need to uh Define these ourselves so if I go into app.js uh let's change this to a raw share material and the difference between a rush air material class and the sugar material class is that the Russian material doesn't have that burial plate code uh the tree just already does um this will crash with our current Shader setup and as you can see here we we we get projection Matrix Undeclared identifier it means we haven't declared this variable also model view Matrix we haven't declared that also and the position also is Undeclared right so uh again those three things that we saw we now need to actually specify and we need to actually uh create them so if I go back into vertex.glsl let's see what the error suggests so we get this error it says prediction Matrix Undeclared identifier let's copy paste this name projection Matrix uh so it seems like this is a matrix and um okay what is this so follow with me um type in uniform Matrix 4 mat4 and projection Matrix so this is a uniform and we're going to talk about what's that uh in just a second but if we reload the page you can see the error message for projection Matrix is gone let's do the same thing for this model view Matrix so we have a uniform uniform mate three um and model view Matrix and if you reload the page the error for model view Matrix is gone let's copy this position and this time instead of doing a uniform uh you can actually see here that this Effect 4 is being constructed and uh this position we don't know what this is but we know that uh the Spec 4 needs four components one is provided here so this needs to be effect three right so we know that uh so uh what is this exactly so the position here is actually an attribute and I'm going to explain what that is but for now let's just do attribute vect3 position semicolon and this is gonna work and we're gonna get our red Shader back but okay now what are these attributes and uniforms what are these exactly so so far we've been just kind of focused on the glsl side of things the share side of things but uh JavaScript and three just need to communicate with shaders right so we need to send data to shaders um and if you remember our triangle example for each vertex in the Triangle we need to actually know the position and we need to send that to the vertex Trader so that's what we're doing here we're uh sending data from JavaScript to this vertex Trader and uh we're sending this vect3 uh position thing now what is exactly an attribute if we go into app.js and if I come down here uh below the geometry if I console log geometry if we take a look at the console you're going to see we get this geometry and the first parameter here the first property is this attributes object if we open that up you're going to see we have a few different uh properties we have the normal we have the UV and we have the position right and I'm going to explain normals and UVS later but for now let's focus on this positions array and this is an array because you can see this is uh float32 buffer attribute type and if you open that up you get this array if you open the array this is just a JavaScript array and what this is doing is it's defining the coordinates of or triangle points uh to construct the sphere right so that's what this array of positions is doing and we're sending this array to the vertex Shader and the vertex shooter is able to draw um our triangles now if you take a look at this item size property you can see this is three and you can see we have an array of floats right so when you have a float when you have three floats what would that be it would be a vect three so that's how this all works together we have an attribute and a sub X3 and we call it position now the same name here is um is applied we have position and uh this is important because uh when you add an attribute in 3GS three just creates an attribute on the glsl side of things uh which you can use um like this so that all makes sense also but now uh what are these uniforms uh what's the difference between a uniform and um you know an attribute and you can see here uh this is a type that I've haven't explained uh so I'm going to explain very quickly here you have a matrix type and this is mate four this is a four by four Matrix so um I made two for example uh will be like um this you have this structure exactly like a matrix for example and uh it's just like an array but it's of course a matrix and uh Yellowstone provides some uh math to actually deal with these now you can actually do maths to X and two again and this would be the same thing because the math 2 was actually a square Matrix so uh you can do this you can also do matte 2 uh X3 uh which is a two by three Matrix and so on so that's a quick explanation of this math 4 type but here we have this uniform thing here um so what does that mean here now if you look into the geometry can we see a uniform here uh if you look through it uh you don't you don't see any uniforms so what is this uniform and where is it coming from so let's go back here and instead of logging the geometry this time let's console.log the material and when you do that uh you get a raw share material and if you scroll down uh you're gonna get this object that is called uniforms and right now it's empty why is that the case well the problem is uh 3GS um creates these uniforms for us uh and we can't actually see it in the Raw shading material here I'm going to explain the difference between attributes and uniforms so as you saw attributes uh was this huge array of positions and for each vertex we have a specific data right so attributes are essentially vertex specific data that we're storing in an array right so for each vertex we have a specific data that makes sense Uniforms on the other hand are a bit different so uh if I come down here and I do materials material dot uniforms and I create just a new uniform um let's call it you um time for example let's just do that I need to do equals and uh I create an object and here what you need to do for uniforms in JavaScript is uh provide a value property so you're going to do value and let's set this to Zero by default now if you console.log material um if you go into the uniforms you can see we have this U time with the value of zero that makes sense now if you want to access this uniform you're going to come down here you're going to do uniform float you time I misspelled here uniform right and this works you get you time in your Shader so that's essentially what three just is doing in the background with these uniforms um it's just passing them in through the material now the difference uh here is that the uniform is the same for every single vertex and that's a huge difference because um for positions we have different positions for each vertex and it's a specific to the vertex that we're currently running this program on but uh a uniform is is the same across all the vertices and a uniform can also be used in the fragment chair so uh you can come here and add uniform Flow To You time and that's uh that will work uh perfectly fine but here uh we have a problem so if you look at this error it says error no Precision specified for float you wouldn't get this error with the Shader material class but with the raw share material class you need to specify a Precision for floats so let's do precision and then you need to specify the Precision so we're going to do medium p and Float semicolon and that specifies the Precision of your floating points and we'll get our Shader um which compiles fine so you can also use uniforms in in the fragments here but uh if you for example copy paste this attribute and paste it here this is going to crash why because attributes are vertex specific data and here there says attributes supported in vertex shaders only all right so you can't use them here so now that you understand attributes and uniforms and how they work uh I want to explain this bit of code um here which is the math uh that is essentially happening in our vertex Shader and then you'll be able to understand how this vertex Shader works all right so the first thing that you need to know is that this model view Matrix is actually two matrices so one Matrix is uniform mat4 model Matrix and the other one is you guessed it uniform mat for the view Matrix and I want to explain what these are in a bit but here we can do a view Matrix multiplied by model Matrix and this gives us the exact same results you can see our Shader composed just fine and um okay so what are these exactly so let me zoom out a bit so we can see the full line here so I'm going to explain these now I'm going to use the term called transform and what transform means is we're talking about the position the scale and the rotation all right now for example the model Matrix provides the transform of our model and the view Matrix provides the transform of our camera that makes sense right so let me write this down here model Matrix um is essentially the position scale and rotation information of our model right and the view Matrix gives us the position and the orientation of our camera and the projection Matrix projects our object onto the screen and it takes into account the aspect ratio and the perspective so we have these three matrices and we multiply them like this and the order here matters so this is often called the MVP model view projection matrices but the order is actually in Reverse so first you need to um write the projection Matrix multiplied by The View Matrix multiplied by the model Matrix and finally multiplied by the position all right so uh that's all that there is to it and with that we're gonna get this now if you for example I don't know uh remove the view Matrix uh you're not taking into account the camera position and orientation so now the camera is um right at zero and I can prove that to you by moving our object so we can come here and we can set icoded position dot set uh and we can set this to zero zero minus five and we're gonna see our object but we cannot move the camera anymore because we're not taking into consideration um the camera is positioned and orientation so uh that's all that there is to it and uh as I said you cannot change the uh the order of these for example if I take this and if I paste it for example here um you're gonna get some weird results because this is not gonna work uh but if I turn this back to where it's supposed to be uh we're gonna get our object um right here all right so now that we understand what's going on here let's clean this up a bit so uh we can remove all of this code and I can come here and cut all of this until the very end we can create a Vic 4 call it model view position and paste uh paste the whole thing here and here if you remember we can replace this with model view Matrix so that's all we need and we can cut this too and create a new vect4 called projected position equals this multiplied by model view position all right so and finally GL position is equals uh projected position right and this gives this will give us the exact same result as before and uh let's let's go back to the share material class so you can remove all of this code let's keep you time here uh because that's our custom uniform uh let's remove this line to Precision float and uh let's keep you time and let's go into app.js change this to Shader material and this should uh give us again the exact same result as before now uh to explain some things uh first let's go back here and uh if you remember we had an attributes object within the geometry so let's console does Vlog geometry dot attributes and when we do that we get something in the console we get an object and we have the positions and the UVS and the normals here now uh what are the positions we already discussed this is the position of our vertices for this icosphere um and um I'm gonna here briefly explain what uh the normals and the UVS are so the normals are the orientation um of an object at a certain point so for each vertex we have a normal right and this is a Vex three and a normal is a vect3 and this gives us the orientation of that vertex on the surface of our object does that make sense I hope it does so um that's normal um and we're going to get into how we can use them in the vertex here later so um next we have UVS and if you open this up uh if you open up the normals too you can see the item size for the normals is three so this is a VEC three and of course there's a float array uh so that's how you know this is the back three and again uh if you open up the UVS this is a float array but the item size here is two so UVS are Vic twos and what are UV uh UVS or UV coordinates well uh when we want to project a texture on our objects for example on our sphere here we use the UV coordinates to do that and UVS are just coordinates um in in the 2D space and we can just map a texture to our object so that's that's what the UVS are used for all right now uh let's go back to some drawings that we had earlier and uh let's recap what we what we have learned so far so um we we know that in order to render things uh we use triangles and um in order to tell the GPU how to draw uh the triangles that we want we use the vertex share and the fragments here now the vertex here tells the GPU where the position of our vertices are and the fragment Shader tells the GPU how to fill our triangle so we already know that uh but we also learned some new things so uh one thing that we learned is that we have a layer uh of JavaScript and we control our application with JavaScript so let's write that down and when we want to send information from JavaScript to to the vertex Shader we use attributes so let's write it down and we know that we could also use uniforms to send data to our shaders so let's write that down too and the difference between attributes and uniforms uh is that the attributes are vertex specific but uniforms aren't vertex specific and we also know that attributes are used in the vertex Traders only so only vertex shears can access the attributes but the vertexure and the fragment share can both use uniforms all right this is the bigger picture of the whole thing the problem is or our sphere that we have right here is is flat and boring right there's no depth uh it doesn't really seem that this is a 3D sphere it looks like a circle the problem is uh we cannot send direct information from JavaScript to the fragment Shader I mean we can but we can only send uniforms which are Global variables now the key piece that is missing here is the communication between the vertex Shader and the fragment Shader so uh next let's talk about how vertexators and fragmentors communicate so uh we already had attributes we already had uniforms and we have another type of variable uh in shaders which is called varyings varyings are used to send vertex data from the vertex here to the fragment shooter so this all now makes sense right we have this thing that is called varying all right that makes sense uh and that's how we communicate but uh if we go back just a bit um let's talk about this a little bit so if we want to send vertex information from the vertex Shader to the fragment Shader this kind of doesn't make any sense because if you remember this triangle that we have we have three vertices here right but within this triangle that we want to render we might have hundreds of thousands or millions of pixels so how can we send data from three vertices to all of these pixels and you might already start to imagine how this will look like but the best way to explain this is by showing you so uh let me uh go back into code very quickly here and if we go into the vertex Shader again remember we can send data from the vertic Shader to the fragments here so we can come down here and Define this varying let's call this varying uh and let's uh let's define this as I don't know vect3 let's pass in the position so we're going to call it V position this is the convention you put a v behind it and you write this in cattle case so uh same thing with with the uniform so uh you can do you plus time and the way that you will send information from uh the vertex here to fragment share is like so you do V position equals position you just uh assign it to a variable in the vertex here and in the fragment share we're gonna copy the exact same line that we have here and we're going to paste this in and here we can visualize how this vect3 will look like so um we can come here and instead of uh providing three components we can do V position all right and with this you're gonna get this very cool result and it kind of looks like our um our sphere is now colorful and we can actually rotate it to see to see what's happening and uh this is now where the fun part starts so now for me to demonstrate uh some things uh let's change this um I could see drawn geometry to a plane geometry all right so let's do one and one and uh that's that's the only thing we need to construct this plane and we get this plane right let's close this I'll assume a bit so what's happening here is that our fragment share is taking the position at every single point and it's displaying it as a color so let's imagine what values we are sending from the vertex here to the fragment share now as you know we're sending the positions right so uh let's think about this point here this is definitely a vertex and we can view this environment frame mode to confirm that so I can set fireframe to true here and we will get a wireframe and you can see this is a vertex and we have two triangles here right uh one is this one and one is this one now uh what's happening here if we comment this out is uh let's take a look at this right what's the position what's the world coordinates um that we have for this point so uh our plane um is one by one uh what's what this means is um this whole section is one unit and this little section is one unit now we can make it two um to make uh this whole section go from zero here at the center uh to one right so let's change this to two and this gives us a much better result now you can imagine that this goes this is the zero position in our world um because our plane is positioned at zero zero zero x y z and as we start to move uh up what we're gonna see is we're gonna reach one one and uh we're going to reach one one in the X and Y directions right we're not making any changes in the in the Z Direction so the Z Direction here is actually zero all right and uh what's Happening Here is we're showcasing this as a color so what is the color with the X Y of one and the Z of zero so if we go into the fragments here we can visualize that we can do a back three and let's put this uh both at one and this at zero that's what we're getting essentially we get yellow that's why we are getting yellow uh here at the top and fragment shares don't understand the values below zero so what's happening here with this dark area is that uh the positions here are getting negative so what's happening here is uh jealous just clamps this to zero um so any value below zero will get uh clamped to zero all right and we're getting black uh we can visualize that even uh if we put vect three zero zero zero of course we're gonna get black right so that's how all of this works and uh the same applies to um to the red parts and uh the green Parts here uh here at the top the position in the Y coordinates is one so again maximum green and uh the red uh which is the x is actually negative one so negative one gets clamped to zero so we have one uh we have zero as the red we have one as the green and the Z is also zero because this this is a plane this is not a three dimensional and this is positioned at the Z uh Z of zero so we're getting zero one and zero and that color is green and so on so this is how this is working and we know that we have two more attributes as well we have U Visa normal so we can come to the vertex Shader here and uh we can create a new varying vect three V normal and we can come down here and just assign the normal to normal remember the the three just already handles uh or attributes and we can just use whatever attribute name these are in JavaScript so here we need to copy this and go into the fragment Shader and paste this in and here let's visualize the V normals so uh what we're gonna see here is is a single solid color and that is because this whole plane all the points all the pixels in this plane are pointing uh this way now we are already starting to visualize things and we don't see the problem that I just discussed um while drawing um so we have four vertices here for this plane one here one here one here and one here and parameter is very smart it's understanding what color we need to put in these pixels so I'm going to explain how that's happening next uh but first let's visualize uvs2 so I'm gonna come here and I'm gonna copy paste this I'm going to change this to a vic2 we can do vuv that's the convention and we can come here and say vuv equals UV again this is provided by 3GS so we can uh copy this go into the fragmenter paste this in and uh here we have the vuvs so let's visualize this now the problem here is that vuvs are vic2 so we need to either put it here uh and provide a value or components here or we should put it um like this and provide a component here at the beginning I'm going to do it like this because uh we get the red and green values like this and it's very easy to explain so here uh we can see the UVS the UVS um I'm gonna explain how they work so they go from zero zero here all the way to 1 1 here so um from the starting point zero zero and uh they start to transition to one and this is one in the x coordinates and uh zero in in the Y coordinates and um we're getting red with that uh the opposite is true here uh so as we're moving up the Y is one here and the x is zero so we're getting green and this final Point here is uh one one for uh green and red um and of course the blue is set to zero here I can set the blue here to one and it will get a slightly different variation but you can start to see what's happening now here's the cool part about jlsl as I said uh we can do sizzling and if I put vuv dot XXX here this provides a vect3 with all the components being a vuv DOT X so once we will get is a value that starts from zero and as we move to the right we get one here but this doesn't explain the problem that I just mentioned earlier so if we go into wireframe mode here um as you can see we have four vertices and two triangles right uh now how does the fragment Shader know what color to put here when I turn off wireframe as you can see we get the smooth gradient so what the fragmenter is doing is interpolation and we can get into what interpolation is and how it works but and there are many good videos out there about the interpolation and I'm going to put some links in the description in case you're interested to see an in-depth explanation of what interpolation is but uh the basic the basic concept here is that if we have one point here and we have my one point here in in a one-dimensional space uh if we assign a value to this point and if we assign a value to this point we can guess the value of uh the points between these two points that's that's interpolation so if this is one and if this is zero we know the middle is 0.5 that's that's how it works kind of and this is also known as lerp and yellow cell uh provides a function uh to us to do lerp so I can go into fragments here so let's remove this and uh let's use alert function instead the lurp function in gel a cell is actually called mix right so we can do a mix and I can mix between zero and I can mix between sorry this should be a big three and a Vex 3 of 1 and we can mix and lurp between those um values zero and one with the vuv dot X so let's use that here so as you remember the vuv goes from 0 to 1. from one side of the plane to the other side of the plane and what we should see here is the exact same result as uh what we saw with vuv.xx so let's go back to vuv dot XXX or you can do RR if you're interested uh this is going to be the exact same thing now the question that might be popping in your head is what if we don't want interpolation uh what if we want hard edges and we don't want uh the fragments here to guess what value is in in between right we want the exact value at a pixel and uh we want to know okay if this pixel is closer to this vertex we want that exact value for that vertex we don't want interpolation so the way that you would work with that is you add a flat before the varying definition when you add flat you disable interpolation for that varying right so you need to add it here and you also need to add it uh behind here in the vertex here so and when you do that uh what happens is you get a hard Edge now this doesn't work because uh we only have two we we only have four vertices here so if I increase the subdivision to for example 10 and 10 . um you're gonna get this hard Edge Look So if I change this to two you're gonna see a hard Edge right in between all right so if you've learned anything new so far give this video a thumbs up and definitely let me know in the comments down below if you like this type of long format content so I can make more of these if you guys like it and with that being said let's continue alright so we've been kind of jumping from one topic to another and I thought that that's the best way for you to start learning the basics and I know very well that this is a lot to take in uh so make sure you give yourself enough rest uh in between these sections but uh perhaps the next chapter of this video is the most important one because we're gonna get into some functions uh available in jlsl and we're going to start to draw some things all right and it's important for you to have the correct mindset um before watching this section now I know as a beginner it is very hard to understand how the vertex sheeter and the fragment shears work uh but the correct mindset here is that all right for the fragment Shader uh we're writing this program and this program is running for every single Pixel in our object and these pixels don't see each other so uh the way that this works is you write an algorithm and your GPU takes this algorithm and runs it on every single Pixel for example in the fragment Shader now you need to think about that algorithm when you want to draw something maybe let's say you want to draw a line um across the screen and we're going to do that um later in this video but uh for example if you if you are using your JavaScript library or something like that you would call a draw line function and the library would take care of that process for you but here in shaders you need to think about okay what algorithm what function do I need to use that takes some parameters and gives me back what I want and again at first this can be really hard to understand and just know that with more experience you're going to improve and get better and better at this and all right so with that being said uh let's see what things we can draw in the fragments here so here back in vs code I have the exact same setup as before I have this vuv.x um that we visualize as a vic3 and we get this uh because we we use the flat keyword here let's remove that and um let's see what we get with this and we get the value that goes from zero here all the way to one uh here at the very end and so the correct way to think about this is that on this plane we have an X and Y coordinates we also have Z but we're not considering that yet so um for for each X and Y we're taking the X and we're displaying the X right so our inputs um are very simple here our inputs are X and Y and the result is X so we're displaying X and in this case this is our algorithm that I just talked about um and here we are visualizing that algorithm through the Shader now there's a site called Desmos so you can just search Desmos and um if you go into that website if you open up the graphing calculator um you can actually visualize this function that we're writing so you can do y equals x that's what we're doing and so if you really zoom in on this um from 0 to 1 because UVS go from left to right zero to one uh we get we're getting this uh this linear pattern now we can visualize this like this here in this graph or we can visualize it here in the Shader like this now if we go back into code as you can see we have this vuv dot X as of x3 so let's change this for example to something different let's do vuv.x multiplied by vuv dot X and now we need to use a Vex 3 here so just wrap this in a Constructor like that and when you go back to our Shader setup you can see we still get a gradient but it's a bit different so if I change this up to if I delete this part and change this back to vuv.x you can see immediately the difference and um the other way to visualize this difference is here at Desmos I can write Y equals X multiplied by X and this is the function that we're dealing with and from 0 to 1 um you can see we we kind of have a different gradient effect it starts slowly and it then it speeds up and both of these meet at one and here's the important part of all of this you don't need to memorize any of these functions you can just uh see what shape you're looking for and you can easily visualize your functions and maybe modify them in different places to get the look that you want right so that's all that we're doing here now if I go back into code uh we can write this like this vuv dot X multiplied by V Dot X but essentially what we're doing is uh this is essentially view V Dot x to the power of two right so we can use the power function in jlsl you write it like this pow and uh it takes the vuv dot X and you can do to the power of two uh remember if this is a float this also needs to be a float so if you do this this will crash let me go back here this will crash and it will says uh pow no matching or loaded function found because um you need to actually put a float here right so if we go back here uh you can see we get the exact same result as before but for now with the power function all right so that's understandable we can do to the power of three and uh you're gonna see we get a slower effect if I go back to Desmos we can do y equals x to the power of three and again you can visualize this in Desmos here too you can see it starts lower than x to the power of two but again these three all end in one place so again different ways to visualize things now uh I'm going to introduce you to another function here and that is the step function so let's write it down step and the first parameter should be this threshold um so we're gonna do 0.5 and vuv Dot X right so vuv goes from zero to one let's see what happens here and what we're gonna get is like this so uh we have zero here all the way and we have um all the pixels here are one now why is that the case uh we're gonna find out but first uh this area is fully zero and uh it's the same as the background color so let's change that very quickly uh let's open up the file explorer and let's go here into render in it and we can change the background color here so we can come here and say renderer dot Set uh clear color that's what you need to do and uh we need to set a hex here so and I can do zero X zero zero zero and this gives us a black but I think I have an extension to edit this so I can come here and I can change the background to be slightly blue blueish yeah that's fine let's change that here and add 0x all right we don't need this anymore um this should work fine so let's go back and yeah our background is now um bluish and okay this step function gives us a hard Edge and if you're interested in seeing what the implementation of this function is you can write step in jlsl in Google and two websites show up one is the Kronos website which is the official opengl website and the other one is the book of shaders now the book of shares uh is a website created by some developers and uh it's a fantastic website for learning shaders so let's click on that and let's see what the implementation is and it gives you some some declarations here and we have the description here and here's the thing this gives you a step like shape right it goes like this and this now what is this function doing well if we go here if you wanted to write this in JavaScript you would write it like this so you take the edge and you say okay if this value vuv dot X is greater or equals than this Edge we're gonna return one otherwise we're gonna return zero this is how you would write this in JavaScript and so the values that are below 0.5 are gonna all be zero and the values that are above 0.5 are all going to be one right that makes sense so that's the step function now you have a similar function to step uh which is called the smooth step and the smooth step is a bit different but uh let's take a look at what it does so you can write smooth step and uh here you need to provide let me just delete this here you need to provide three parameters so the first one is the minimum that you want uh to smooth step so um we're gonna do Point uh 45 here and the maximum we're gonna set it to 0.55 and here you can see that I've tried to kind of keep the values around 0.5 uh the same as we had before with the step function and here you can provide the uv.x and if we take a look at the pattern now this is a smooth step uh this is like a step but it's smooth now this is not exactly how you should be using this function because the implementation of this is a bit different so if I come here into the book of shares uh let's create a new tab the book of shaders smooth step let's search it up and uh click on this and if we scroll down you can see the shape of this function is like a step but um it's smooth right so that's exactly what we're dealing with and here in this website you can actually uh change these values so here we have our smooth stuff function uh we can change this Min value to move forward which is what we did uh we put this at this and this so you can see the effect that it has here now all you need to understand is how this function actually looks like so if we scroll up in the description here we have the function definition uh so you can see the algorithm behind this function and it's a bit weird so you don't need to memorize it uh just memorize how it looks it looks like this so okay now that we understand smooth step let's move on uh to the next function the next function I want to talk about is length and length gives you the length of a vector so if you provide vuv which is a vic2 you're gonna get a slightly different results now this is starting at zero here and as we're moving away from 0 0 here uh we're trying to reach one and here we're reaching one right so um actually what we can do here is create our own UV variable so we can do Vector UV vuv and we can modify this UV now and you really cannot modify vuv itself for example if you do view V equals back to something this is not going to work because bearings uh cannot be modified from the fragment shooter so this is going to crash um and yeah you cannot modify a bearing so uh let's remove this but if you store it um in a new variable you can now modify the new variable so what you can do here is we can change the UVs so right now if I comment this out right now the UVS go from zero to one here zero to one here and we have one one here right what we want is we want to move this black point to the center point here okay to get a circle like shape and I'll show you what what I mean um here it's very easy to do so we can do UV plus equals vic2 and all we have to provide is 0.5 so if we add 0.5 to the X and A Y it's going to move up and if we use this now as the input we're going to get a weird result we wanted the black uh dot to be in the middle but it's not so we we might be making a mistake here let's modify this to minus equals and there we go so sometimes you need to experiment uh with your math uh and of course the reason behind this is obvious but um yeah sometimes you might forget um how to actually do stuff and you experiment until you get the right results so maybe we can multiply UVs by two and see what's happening and there we go so now it goes from zero all the way to the minus 1 and -1 x and y and the same here and the same here and the same here and now we're getting this circle like disk like shape and we can now use some of these functions together so if we use a step for this function remember we need to provide an edge so let's do 0.5 we're gonna get a hard Edge so if I want to modify the radius of the circle if I increase this value we get a bigger Circle so we can we can create a const float we also have const in jlso so we can do const float radius equals 0.8 and here we can come here and say radius and the convention is for constant values you're going to use uppercase um letters so with that you're going to get the exact same results and we can now modify this however we want now something that we could do here is we could use a uniform to change this radius all right so uh let's make this a uniform so let's change this back to U radius now let's create a uniform here at the top uniform float U radius and we can come to app.js and create a material that's uniforms.u radius we can create an object with the value of 0.5 for example and here we have access to this GUI GUI uh class so what we can do here is we can add GUI dot add and uh what we want to add is material dot uniforms dot U radius and what we want to change here is the value parameter so if we add that we're going to get a value parameter here and here we can change this value so we can do 0.8 we can do 0.9 we can do two and this gives us a full black screen so we can do 0.1 we get a small little circle here and you can see how we can use this to to create different things so let's make a range out of this let's put them in at zero and Dot Max at one and this is going to give us a range to work with so you can change the radius like this and as you can see here in the fragments here we're designing an algorithm to draw a sphere so very simple stuff now some people will tell you that it's okay if you're not good at math in shaders and um I don't really agree with that because all we're dealing with here are mathematical algorithms and this gives you so much power but you also need to be good at math now you don't need to be good at math from the start I definitely wasn't good at math when I started learning shaders but you have to always keep in mind that you need to improve your math skills and you're going to highly benefit from knowing math when it comes to working with shaders and again if you're interested in learning the implementation of the length function you can just search that and let's go into this Chronos website this time and this description gives you a full explanation of the algorithm so length Returns the length of the vector in other words uh this mathematical formula so now this type of writing things reminds me of something so if we go go back here in jlsl you also have another option that you can use you can do to access ub.x you can do UV and treat it as an array so the first item you can get that and set that to for example I know whatever 0.1 and this will compile um and this will of course change the result but um this will compile fine because this is valid in jlsl you can also do a UV um treats it like an array one this is UV dot y so this is also available in in yellow cell all right so the next function that I want to talk about is the fract function so let's remove all of this let's just copy copy it here and we can comment it like this and here um we need to parentheses all right so here I want to talk about the fract function you have a function in jealous called fract and you pass in vuv.x as always a wrap this in a big three Constructor now this fact function is very interesting what it does is if you have a number let's say let me expand this a bit let's say you have a number and um let's say that number is 0.5 or 2.5 what's the fact function does is uh it only gives you back the decimal all right so in this case uh it just forgets the two and it gives you back 0.5 if you had 3.5 it will also give you 0.5 all right so you can see when it goes up to one it restarts one by one it keeps restarting so if you take a look at this um for example if you search fract glsl if you take a look at the shape of this function here we have the book of shares Oracle uh the shape of this function is like this it goes up and it goes down it goes up it goes down it goes up and it's creating this Spike like shape like this the reason that this is not showing anything is because we're only in the zero to one range with our vuvs so let's change that let's come here and multiply vuv dot x with 10 and here what's going to happen is vuv.x now goes from 0 to 10 right so if you multiply the range by a number both the Min and Max of the range will be multiplied by that number so arrange here for vu.x uh is from 0 to 1. so let me write that down here when you multiply this by 10 what you will get is you will get zero again because zero multiplied by 10 will be zero and ten right so now you're getting this range uh for for the domain of this function all right and you're going to get this and if you take a look at the graph uh it goes up it goes down it goes up it goes down it goes up it goes down and we're getting the exact same thing here all right so now you're getting these Stripes here um and if you really want clear Cuts stripes with hard edges what function would you use uh whenever you want hard edges you pretty much always use the step function so let's first of all comment this so that we have it and we don't need these anymore let's again copy this so we're gonna come here and say okay step apply to this function we can do 0.5 again if we wrap this around this step you're going to get stripes with hard edges now another function which you could use instead of fract is mod now mod as I described does not exist like this in jello cell you need to actually use the mod function so we can come here and instead of fract we can do mod because it's it does a similar thing mod of one for act so fract when it goes up to one it restarts and the mod here is the exact same thing but you can change that parameter it can go up to two and restart it can go up to two and restart all right so that's how this works now um we can set this to one and we're gonna get the exact same thing as before we can set this to two and you're gonna get a slightly different result of course um and you can also go three four five you can increase the number um and this is very cool right so you have full control over what functions you can use and what pattern uh you can create with these now we're going to use this mod function later in this video to create that final animation I showed you in the beginning so uh this is very cool let's uh let's keep all of this in one comment now the next function that I want to talk about is a mix and this is also known as lerp now there are many videos on lerp so um I recommend you go ahead and watch a few different videos on lerp itself because it's a very useful Concept in three Graphics in general but here uh we can um we can do 0.5 up to one and what this will do is whatever we provide it will lurp uh from point five to one so we can provide vb.x and what happens here is this is going from 0.5 at the very left here all the way to one and we can change this range we can do 0 to 0.5 so the reverse of that kind of and here we're going to get zero at the very left and 0.5 at the very right right so this is how this function works now this also works for vectors vectors Etc um but I thought I just introduced this to you and this can have its own video honestly so make sure to do your own research on lerp it's a very useful concept and 3D Graphics now I will not explain it because uh if I wanted to explain these things this video would be 10 hours okay so the next function that I want to talk about is the dot product so let's cut this paste it here and for the dot product I'm going to explain the algorithm because uh it's a really important function so the dot product is written like this it's a function in yellow cell and it takes two vectors so so it takes Vector a and Vector B let's define these here at the top so I can define a vect three let's call it Vector a equals vac three Vex three maybe one and let's define Vector B uh let's put this as zero and what the dot product does is very simple that probably gives us a single value at the end so we can do float uh dot product let's just call the variable that so here I can input these Vector a and Vector B and this should run if I put the dot product here to visualize it uh this should work fine now we're getting a value now what is this dot product doing exactly so the algorithm behind that product is like this you take Vector a dot X you multiply it by Vector B dot X you add it to Vector a DOT y multiplied by Vector B dot Y and again add that to Vector a DOT Z multiplied by Vector B dot C and this can also be applied in 2D so without Z but um yeah this is the dot product now why is this useful and what does it do so when I think about the dot product I think of the shadow of a vector on top of the other Vector so um with the dot product we're dealing with two vectors so let me draw two vectors here and what the dot product does as I said is it's projecting the shadow of a vector onto another one so uh what does this mean so if I pick a yellow color um and if I draw a sign up here you can see that the sun will cause this Vector to cast a shadow on top of this one and while how does this work well if you take this uh the length of this Vector as zero and uh if this is one uh we're getting a value in between zero and one and it could be for example 0.7 here and here 0.7 will be the dot product of these two vectors now this is as I said very useful uh so let's check out one of its use cases in the fragment Shader all right so let's check out one of my favorite use cases of this function so let's delete all of this and let's create a vect3 called it view Direction and this will be equals okay so um 3GS also provides another uh uniform to us and that is the camera position so let's just put this at camera position and let's visualize this as color right so we have this uniform so we just provides it we get this if I change the view you can see the color changes now I want the view Direction in this case so how can we find this view Direction Vector in a given point uh on on our object so let's go back to the drawing board here and let's say I have a camera right here and I want to render the sphere now for this point for example and we want to see what the view direction is uh so this object is placed at a certain point so uh let's just say it's centered at the origin of the world uh zero zero zero and um so we have two vectors here one is the camera position if I draw it like this we have one vector which is the camera position it goes from Center to this position and the other Vector is this the the position of the vertex itself um so if I draw the vector of that you're gonna get this now if I want a view Vector I need to subtract these two vectors from each other and this will give me this part but the problem is this Vector could have a very big length or a very small length but I just want the direction so when you want uh to just know the direction of a vector you normalize it all right so if we normalize this vector uh we get our view Direction so so let's Implement that uh so here I can do V Direction equals camera position minus um and as I said uh we need to subtract the position so V position and this gives us uh that Vector that I talked about but we need to normalize it because we want the direction only so um and this way we get the view Direction now if I take a look at this again if I change the view you can see this gives us this cool effect now if I if I do this on a sphere it would be much better so let's change our object now to to be a sphere let's do sphere geometry with a radius of two that's fine and I think that works that works for us maybe I need to increase the subdivisions um no that's fine let's just keep it at one uh yeah and this is going to give us a sphere we can rotate it and uh for each point on the sphere we're getting a different view Direction right now what I can do with this view direction is I can take the dot product of this view Direction with the normal of a point and this gives me a very cool effect so let's see what I'm talking about here again remember the dot product gives us a float so float and I'm going to call this fresnel because that's the effect um that we're creating this is the fresnel effect um so we can do dot of this view Direction and are V normal so two big threes and this gives us the final now let's visualize what this looks like uh we need to construct it as a vic3 and this gives us this spherical shape where we have one here at the center and as we move to the edges we get zero right now if I I can remember this so if I revert this this gives us the fernel effect where we have [Music] um where we have zero at the center and as we move towards the edge this gives us one and as I said the dot product projects one vector onto another and in most cases what you need to do is you need to normalize these vectors to get the direction now what the normalization does is the normalization uh sets the length of the vector to one all right so if you use the length function on a normalized vector you will get one now um okay so the the dot product projects one vector onto another how is this useful well when you normalize two vectors you can actually know if the direction is the same or not and if the dot product is one you know the direction is exactly the same if the dot product is zero you know that these vectors are perpendicular so here you get one here if I project this I get zero right that makes sense now What's Happening Here uh with our example is that the view direction is directly looking at the center point and if I remove this for a second what we will get is one because uh here at the center The View direction is is completely in the same direction as the normal and as you move towards the edge the direction of the normal changes because the surface orientation is now pointing this way and the normal becomes perpendicular to the view Direction which is straight and this gives you the dot product of 0 here at the edge now if you invert this for example put one minus dot this gives you the fresnel effect and we can type the fernel effect in Google so um if I go into images the final effect is this effect where every object is dark in the center and as it moves towards the edges it becomes light and you can use this effect to enhance your model's looks so for example here you have two images one with fresnel one without fernel and you can see the difference is night and day every natural object has fresnel and these are some of the functions that are available in glasl you also have the cross product but we're not going to talk about that in this video just know that it's available so now that we figured out how these functions work let's move on to drawing some interesting shapes all right guys so here I have a list of things that we can draw so the first item in my list is drawing a line so let's remove all of these lines of code uh very simple stuff and let's change this back to a plain geometry because it's easier to draw stuff on a 2d plane so let's use one one and that's it um we should get something uh but I guess okay where else putting fernel here let's do vuv.x okay now let's um increase the size of this so two and we get this all right uh we go into the fragments here and we want to draw a line all right so uh where can we start well when we want a hard line we probably need to use step right so we just keep that in mind but uh but how do we actually you know how to actually Define a function that draws the line with a step for us well something that I can think about is if I want to draw the line like this here at the here at the center we should have more values that are close to one and here are the edges we should have values that are close to zero that way I can step this and get a hard line let's see let's see how we can do that so the first thing I need is a function that makes this area zero this is already zero all right and makes this area also zero and here at the center we want uh White right we want one right so one thing I could do is playing around with this value let's um subtract 0.5 here so we get this all right Val the values are going from minus 0.5 here 2.5 that makes sense now I want to function that can actually um you know take this pattern and copy it on the other side right so here we have negative numbers what if I could somehow copy this part onto this part and uh from experience I know a function does that uh so if I come here and if we uh display the apps the absolute value of x this is exactly what we need so the UVS go from zero to one all right that makes sense but if we subtract 0.5 so if I subtract 0.5 here this is going to move like this and if I if I don't apply an apps we're going to get exactly what we're getting so we're getting Point minus 0.5 here and uh when we go up to one we get we get 0.5 all right so that makes sense if I put an absolute value here so um if I do this we're going to get the absolute value and uh this might look like something useful so uh let's try this out let's see what happens so if I go back to code I can use an absolute value here now we can revert this so let's come here and let's do this one minus this this will invert uh the whole thing so we're getting a white line here but it's smoothly transitioning into something here at the edge now I don't care about that something I can just uh step this and um for the threshold I know 0.8 and we're gonna get our heart line that we wanted from the beginning so there we go I can increase this um and get a get a thinner line so let's do 0.99 and we're gonna get a very thin line all right so that's our first exercise and uh the other thing I can do here is instead of vuv.x we could do vuv dot Y and this is going to give us a horizontal line right so all right that's that's done the next item on my list is drawing a circle now we already did this so uh let's just copy this and let's say line this and okay so we now want to draw a circle so um for a circle we did try the length function earlier so length of VV itself and we need to put this in a Vex three so I'm here and do that so if you remember we get 0 here and it goes like this so we need to subtract 0.5 like this to um make it go in the center and we can step this to um get our Circle so you can do step 0.5 or the U radius that we created earlier and sorry about that and we're gonna get this right sweet we can decrease and increase the value but uh what if we want to do this another way uh let's let's explore and see what's possible so I'm gonna copy paste this here all right so let's see if we can come up with another solution to this circle problem that we're trying to solve all right so let's copy this part again and let's see what we're trying to achieve so another way to do this is if you take a look at this we have an origin point and each and every pixel is drawing the distance to this origin right so if the distance is zero we're getting zero and as we're moving up the distance is actually the factor that we're drawing here so um I can change this maybe to the distance function um but the distance needs to compare to some value so if I create a const a vector Center this is going to be the center of our uh Circle so I can do vect2 zero let's put it as zero for now and let's compare the distance of the vuv coordinates um to this zero value so let's just do distance of vuv to Center and we get the exact same thing right but this time we can actually modify the center to be to be in whatever position we want so this is a nicer way to do things maybe we can come here and create a function call it I don't know float draw Circle and this takes a position and we have a center we can actually pass this in as as a parameter two so let's do position and Vic 2 Center all right delete this and we can return the distance of the position to the center and we can return that so here we can come and say draw a circle we're going to pass in the view v as the position because it's a coordinates that that we want to deal with and here at the center I can Define anything but let's do 0.5 and here we're going to get the exact same thing all right so we can do a step here actually to replicate what we had um actually let's do radius let's actually Define radius here as well and here we can pass in um radius so a radius can be U radius all right that makes sense and we get this and we can again control everything and now this is a little bit different than uh what we what we did with with this formula but in terms of math it's exactly the same thing now this gives us a little bit more control over over our parameters and this is a fantastic opportunity for me to introduce you to sign distance Fields so I'm going to write the downside distance fields and this function is essentially assigned distance field because for every position um in in our plane in our world in our 2D World um we're getting a distance and if that distance is below zero we know that we're inside the object if that distance is zero we know we are on the surface of the object and if the distance is above zero we know that we are outside of the object okay that makes sense now people have invented many different sdfs uh over the years so we can search for SDF of a square and the first site is from Inigo Quilla so let's open that up and if we scroll down we can maybe find yep the SDF of a box so let's copy that and let's put it here as the function now this takes a position so this is the UV so uh and and probably the spec 2 is is the size of the box so let's copy paste this uh so let's first let me comment all of that and we can come here and say SD box and we can input the UVS Okay so that's our position on our plane and here we can um we can determine size of the box so let's set it to one and let's see what we get and okay we get a black box so we need to put 0.5 here maybe and there we go we see something uh maybe we can offset our UVs to be at the center um and then we can maybe again drop this to 2.5 and again it can maybe drop this to I don't know zero points 15. so yep we're getting a box shape and we can invert this uh to get white where where there is a box and okay uh maybe we can use this step function here again let's use points nine and let's see what we get with this and we get this okay so there are many sdfs that we could use um to to draw different shapes and patterns and this is just an example of that okay so uh this opens up a whole a whole set of opportunities for us to explore different functions that other people have invented uh one particular function which is very interesting is Berlin noise and I have the code of pearly noise here so let's let me just copy paste that here um all right I'm going to copy it and I'm going to come down here and uh we're gonna comment all of this code because it gets in our way so let's just paste this implementation in and this is a Long Function uh that does some crazy math we're not going to get into what math this does but this is called noise and it takes up like three so so if I come here and let's first of all save this so let's delete and paste here all right and here you can use noise and you need to provide a vic3 in this case there are two denoises too but uh here I picked epic three so we can provide maybe the V position and get different noises at different values and you get this which is very interesting now um two two scale this up uh you can multiply this by a huge number the V position to get a better look at uh how this actually looks and you're you're seeing some smooth noise here right uh so there are many videos made uh on the topic of parallel noise and we're not going to get into depth um of uh what parallel noise is but definitely make sure to do your own research on this because parallel noise is very cool another version of this noise is simplex noise um and uh you see people using these noises to create smooth patterns and organic shapes and in fact in the final project uh in this video we're going to create uh our smooth noise animation uh with this exact noise all right so next I want to show you how you can import images uh into your shaders now um let's comment this out so I'm gonna copy paste this here let's go into app.js and here I'm gonna create a new uniform uh let's enter this material dot uniforms that Hue texture okay so we're going to be importing a texture and we're going to be using the 3Gs texture loader class so uh new three texture loader all right and we're gonna use the load function so after initializing this texture loader you can do load and here at the top of this file I'm going to import an image now uh if you look at this repo here that we have in the images folder I have this image.jpg um which is this colorful image let's close that and let's try to import it so here I'm going to come say import colorful uh texture from and we're gonna do images image.jpg all right this is going to import the texture and we need to copy paste in this into the load function here so just copy paste that in and here we added it to the JS side of things but here we need to actually use it in in the fragment tutor so you can go at the top of the file here and you can use this as a uniform so uniform sampler 2D that's what you need to use for 2D textures you're going to use sampler 2D and the name of the texture is you texture so write that down and all you have to do now is get the color of it now the function that you need to use here so let's do next for color is texture 2D all right so texture 2D and uh use the name view texture and you need to map this onto the object right and the uv's UV coordinates are just made for this so uh we're going to use vuv second colon here and here we're going to do color dot x y z all right so that's all you need to do and with this um if we reload the page we're going to get our image very beautiful stuff now I want to show you a really cool trick that you can do in the fragment Shader with the dot product now this is another useful case of using the dot product so I'm going to paste this constant value here desaturate and this is a magical Vic 3. so we're gonna what we're gonna do is uh let's actually change this to a Vex three color and you can do swizzling here uh to store this XYZ and let's delete this so the dot product of the desaturate constant here and this color will give us the saturated image all right so let's um validate that statement that I just made so we can do float final color and set this to the dot product of this desaturate constant and this color and what the dot product here does it uh it actually gives us a weighted um a weighted way of showing the brightness of the image so you're going to see what I mean by that so let's just visualize this next three final color and we will get this uh which is pretty cool we get the desaturated image now the way that this works is the dot product also in this case creates some weights for the color components and the reason that this magical number works is that your eye is very sensitive to Green right so the green here has more weight and uh after that is red but it's not much and after that is blue so we're using different weights for each component of the color and this final color gives us the desaturated image and that's it for this section of the video next we're going to be implementing the final project that I showed you in the beginning of the video um and I know this is a lot to take in definitely make sure to rest in between watching these sections and um of course with more practice uh you're gonna get better guys all right so um I know I I touched on a lot of different topics and you need you don't really need to memorize these um all you have to do is practice and uh you can you can just come back to this video uh whenever you feel like uh you you just forgot something all right uh so that's it uh let's move on to the final project of this video all right so the project that we're going to be implementing is inspired by this artwork from ducky 3D now uh he has made a video tutorial on this and uh all the credit goes to him of course so I definitely like this video And subscribe to his channel as well and what we're going to be doing is we're going to be taking a look at his process of making this in blender and we're going to take that process and translate it into a process that we're going to be using to create this in 3js all right so we're gonna hop back into code and we're going to be deleting uh these pieces of code and I know a lot of you guys might be interested in keeping these so uh what I'm gonna do is I'm gonna create a new terminal I'm gonna create a new Branch you can check out uh Dash B and we're gonna call this shapes all right so um so we're gonna do gits at dot uh this will add all the files and we're gonna get comments Dash M save or something all right so I'm gonna be pushing this Branch into our project repo and you guys can check it out from there so let's create another Branch you can check out Dash B and let's call this organic all right so now what I'm gonna do is I'm gonna go through our shaders and I'm gonna delete all the unnecessary code uh so that we can start from a basic Shader from scratch all right so now what I have in my vertex Shader is very simple we have this uniform Flow To You time uh which we update in our animation Loop and we have these three varyings the position of V normal vuv and we set them here and we have the MVP model view projection matrices um math and that's basically it in our fragment here uh we're just uh having the same thing so uniform floats you time our bearings and uh we're just outputting a simple red color now in our app.js what I'm doing is I'm just setting this uniform you time um to this object uh with the value of zero at the beginning and as I said in our animation Loop here we're going to come and we're gonna update this so we're gonna do material dot uh uniforms.you time and uh what I'm going to do is I'm going to set the value to the timestamp all right so now this might be a little bit too much so let's do time equals timestamp and let's divide this by a thousand now let's do that so uh with that we have our basic setup here and with this you're gonna get this um red plane all right so what I'm going to do now is I'm gonna come to this video and we're gonna try to replicate the process of this so first I'm going to try to create the pattern on a plane um so the first pattern that we're going to see in this video is this tripe like pattern um with these lines and we already covered this um so this is very easy to do so what I'm going to do is I'm gonna do this in the fragment Shader and uh we're gonna create a Vic 2 called the TUV and store vuv in it so that we can modify the UVs and uh if I remember correctly we're gonna be using a fract so um let's just do fract and uh let's just put the UVS in here and what I'm gonna do is I'm gonna just take the UV dot X and uh of course this is not gonna work because the uv.x is always between zero and one and we need to multiply this by a value like 10 and with this uh this should work now we need to wrap this in a vic3 so let's do that and let's see the pattern that we get and yeah we get this stripe like pattern now uh the problem is um we're getting this gradient almost here uh so what I'm gonna try to do is I'm gonna try to uh use a step on this uh to get rid of that um gradient and we can have some hard edges here right so yeah we get the pattern that we need uh now um let's apply this on a sphere because uh this is applied on a sphere so let's go ahead and change this um geometry that we have to a sphere geometry let's set the radius at one and we're gonna get this uh which is pretty cool but it's not what we want because um this is like uh not going from top to bottom uh it's kind of going from side to side so maybe what we need to do is use the UV dot Y and let's see what we will get with this okay this is this is uh interesting uh we're getting something very similar to the video here and the next thing that ducky 3D does is he Loops uh this with an animation from side to side so that's what we're going to be doing next um so let's come here and let's change this UV dot Y and let's add you time here and we're gonna get our animation now it's a little bit too fast so uh let's again um add another zero here and yeah we get our smooth um slow animation alright so uh next what he does is he makes this pattern smooth now um there are many ways to do this but uh one quick way that I thought um we can do this is actually uh if we come back here we're using a fract uh let's not do that let's use a mod um because we want to be able to control the space between our lines so what I'm gonna do is I'm gonna come here and say mod one now um this is going to give us the exact same result uh don't forget to make this afloat as always and this is going to give us the exact same result but now what we can do here is we can search for a smooth mod function and this hopefully will smooth out our pattern like here now let's see if that uh thing exists so I can do smooth mod glsl and it looks like we have something so let's click on this website I'm going to scroll down and I'm going to copy paste this code so uh let's also copy paste the comments above it and um I'm gonna come here and paste this in so smooth mod by this guy all right um and or let's take a look it has some documentation as well so uh we first have an axis so input X is to modify and we have an amplitude of each Edge or tip we have a radius uh for each Edge or tip and it Returns the smooth edges all right so that makes sense uh let's come here and try this out let's use this instead of the mod that we're going to be using all right so um now this seems like uh what we already have here the amplitude um but the radius uh we can actually change so I'm gonna put the radius at one and let's see what we will get uh with this function so uh we get nothing let's check why that is so if I open up the console uh you're gonna see this uh line Pi is a Undeclared identifier so uh Pi doesn't exist um so we need to actually Define this pi value uh that this introduced all right so here might be a good opportunity for me to introduce you to macros in jlsl so we can do Define hash Define and this defines macro Angela cell all right and a macro is simply if you put Pi here and if we put 3.14 uh like this um we can actually replace um parts of the code with this macro and at compile time it's going to replace uh the whole macro with this um parameter that we provide and what that means here is that we're using this Pi variable here and uh at compile time it's just gonna put this at 3.14 and macros are of course not variables the difference between macros and variables uh is that the macros are always defined at compile time and not at runtime so um we're gonna put Pi back here and what I'm gonna do is I'm gonna replace this part with a pi value with more Precision all right so I'm gonna paste this in um this has more precision and uh you don't have to put a semicolon here because uh if you put a semicolon here it will replace Pi with a semicolon so you will get uh 3.14 uh with a semicolon after it and that of course uh leads into errors so you you shouldn't really put a semicolon there so yeah we're gonna get this now um this is the exact same result uh this isn't smoothing anything so when we maybe we need to change the parameters here my guess is that we need to now get rid of this step function because the mod function already does the smoothing for us so we can just remove that and we're gonna get this uh which is pretty cool all right so I experimented with some parameters and what worked for me uh was this so change this to 1.5 uh this radius parameter and what you need to do is actually set this to a higher value so if we set this to a higher value you're going to get more lines uh very similar to this one but this still looks off a little bit so what we can do uh to make it look like this um is we can scale these values uh to fit in a certain range this is already smooth but we want these valleys to fit in a certain range right so what I'm going to be doing is I'm going to go back into code and I'm going to use a function that I pretty much always use in my projects and this is a math function so let me just copy paste it here so here I'm going to paste this this is the fit function which I always use to fit certain values in certain ranges uh to another range right and this essentially scales it so uh we have this unscaled and we have this original Min original Max and a minute loud and Max allowed alright so let's take a quick look at this and the values that we're getting uh are kind of like similar to each other and it looks like uh this is going from something like 0.2 um two all the way to 0.7 or something like that so so let's copy this entire thing and let's put it in effect three uh variable like three color equals this and what we can do is uh actually we need to take this as a float and let's call this pattern um and let's put pattern here all right this should work the same as before and what we can do is now fit this into the range that we need so as I said um the original Min and Max might be something like 0.2 and 0.7 so that's the original um range and the range that we really want uh is zero and one so this is gonna scale this to fit this range so um as you can see that works uh somewhat uh let's uh also set this to 0.3 let's see how that works okay we get more dark areas like this and also let's change this to I don't know 0.6 let's see the effect that that has um and yeah this is starting to look exactly like this all right so uh with the values that I experimented with um while I Was preparing this video uh I came to these values so uh let's change this to point uh 35 and this should be 0.6 um that works nicely and we get this pattern uh which is extremely similar to this and uh let's let's now move forward all right so and the next thing that he does is um he plugs this noise texture uh thing as a vector into the wave texture um or the wave um node here so we already kind of have this wave node um we can maybe uh make a new function call it I don't know float wave and it takes a variable a vic2 called position uh this is normally what I call my um variables so let's take this and let's put it here uh let's return this so instead of UVS here I'm going to do position.y this should work fine so we have this wave function all right so let's come down here and do float pattern um equals wave and let's pass the UVS in and this is essentially going to give us the exact same thing all right so um what we can do now is we can uh plug a noise texture into this UV but how do we actually do that so uh first let's copy paste uh the Pearly noise implementation which I showed you guys earlier all right so let's come up here and let's paste this in uh classic purlin 3D Noise by Stefan Gustafson all right so and this gives us this noise function uh which takes a big three and the reason I'm using the 3D version of the parallel noise is because we're dealing with a 3D sphere right and for 3D objects I always use the 3D Pearland noise and um all right so let's copy this let's come down here and uh let's see how we can deal with this so uh I think the name here is a bit confusing uh so let's change this to UV name uh first of all um the thing here is this UV is actually a Vic 2 but or parallel noise uh function needs a vic3 so uh the way that we can fix this is uh instead of using the UVS we can use the normals all right so we can do we normal and their normals are vic3 uh if you remember now let's change this um parameter name into something better uh what I'm gonna do is I'm gonna um name this quartz or coordinates all right so um you can also call it position but I'm gonna call It chords so uh this should be a victory now and also this is gonna break because this takes a big two let's change that to take a Vic 3 and with this everything should work the same as before uh we even get more lines uh so uh what we did here uh we should change this to something like six or something and uh yeah we're gonna get the exact same thing but now with the normals all right so if you take a look at uh what ducky 3D does uh Becky 3D uh uses the noise texture as the input for this wave texture all right so we need to somehow um change This chords to do something right so what we can do uh to change This chords uh variable is we can do chords plus equals and we can distort this uh with a noise so let's do plus equals noise Maybe and let's use the chords as the inputs so we're going to get this and uh this is the exact same thing that we want now the problem is you're gonna see these your lines here um and um this is because we don't have enough subdivisions in our sphere so I'm gonna hit come here and let's also change this sphere geometry to an icosahedron geometry that gives us a better spherical shape so let's uh put the radius at one and let's uh set the detail at I don't know 50 for example and yep we're gonna get the exact same thing because the math is exactly the same so uh let's rename this to something else uh let's do Vex three um let's call it noise pattern all right and we're gonna make this like this and we can pass this noise pattern into this all right so everything now is nice and clean um now we're getting this shape and let's move on with the tutorial uh if we continue um again we have the exact same setup here the next part is displacement all right so so far we've kind of been in the fragment Shader and we've kind of um played around with uh the values and uh we kind of got this to look the way that we want it to but next we want to do actually uh some displacement with the geometry and uh as you guessed uh we need to now move this algorithm to the vertex here all right so let's copy all of this code uh and we're gonna move everything to the verse extruder all right so uh we're gonna come here and here let's put a comment here stating that this is the bearing section and all right um here I'm gonna paste all of this code let's move all of these lines uh like this now um of course here in the vertex here we don't need to use the V normal we can actually use the normal and everything else should be fine now we need to uh take these functions and let's go up up to this point so let's copy everything here um let's paste all of this code in all right so this should give us um a normal sphere and everything should compile fine uh of course I need to set a value here let's actually create um another varying uh it can be Avec 3 but let's do float wiring float the displacement right uh so we're gonna copy this and we're gonna come down here uh place to send and redisplacement can be equals to this pattern that we have so we can have our pattern here actually let's move all of this code um above everything else so we have our main function here and we set the bearings all right like this in one place and let's put a semicolon here um and here what we can do is we can output this Vic uh at with this as of x3 so let's face that in and we're gonna get this um now the reason you're you're seeing this uh issue um is because our vertex Shader now is responsible for creating this pattern and the number of vertices are much lower than the number of pixels that we were dealing with before so what we can do here is we're going to come uh into our code and in app.js uh let's change this to 100 and uh you can see this fixes the issue because we now have um much more vertices [Music] um and those are handling the pattern nicely all right so uh let's go back here and now what we're gonna do is we're gonna displace this uh so for this uh let's go back to the drawing board okay so here we want to displace the sphere and um the result that we're looking for is something like this uh where we apply the noise to the surface of the sphere and uh we should be able to get something like this orange outline at the end right all right so here what we want to do is we want to elevate each vertex to reach this position right so we want to elevate this Elevate this to reach this displacement right and uh the only thing we need for this uh displacement and you know changing the position uh is first we need the direction so we need to know in what direction we're going to be pushing this vertex in right so our vertex is going to go from here to here um and the direction here is important right so that's the first thing the second thing is how much are we going to push this vertex in that direction so these are the two questions that we need to answer here okay so the first question is what direction should we use for each vertex and if I draw each vertex direction that we want uh all around the sphere you're going to see apparent um showing here right so if we draw uh this part um where the direction goes inside the sphere and this part they are all going to reach one single point so uh like this like this like this like this and this point is the center of the sphere right so the direction here is the direction of a vector that goes from the center to the vertex on the surface right and in this case uh the direction is actually the normal of our sphere all right so uh the normal gives us the surface orientation and it's a vect3 and in this case it also gives us the direction that we need to be pushing these vertices in right so that's the first question uh we need to use the normal uh to define the direction right and uh the normal is already normalized so uh you already know that the normal gives you a direction and an orientation right uh the second thing that we need is how much should we push these vertices along this normal direction right so the answer to that is we need to push these vertices by the noise Factor right so if we want to get this noisy shape we need to when the noise factor is higher for some vertices we need to push it higher along this normal Direction so let's Implement that very quickly here all right so what I'm going to do here is I'm gonna come into this vertex here and I'm going to create a new variable call it a new position all right and uh again we need two factors right we first need the direction that we should push the vertex in so that's going to be the normal and how much should we push that vertex in that direction uh the answer to that is our pattern here or we can use the V displacement uh because we are already uh assigning that to the pattern all right so just to keep it clean and we're going to use the V displacement uh and let's check this uh let's see if this is working or not um so let's uh paste this in and let's go into here and yes we are able to displace our sphere like this now there are multiple problems here of course uh one is this Jagged Edge which we're going to fix later but the other one is uh our displacement is starting from the center point here right and this gives us a a bit of a weird look right so if you'll take a look at the displacement that uh ducky 3D has um if we go back here in the beginning displacement that he has is is very subtle right it doesn't start from the center of the sphere so the way that we're going to be able to fix this is uh we can come here and uh here in this position we can actually add all of this to the existing position now this way uh we're taking the position that the vertex is already in and we're pushing it along the normal by some value all right and that's going to give us a much better result and this is going to give us this result now uh this again uh has too much displacement in it right so we need to maybe um turn this a little bit down so I'm gonna do since I'm going to come here and call this float displacement and take this V displacement uh divided by three and uh use the displacement here and this is gonna give us this result uh which is pretty nice now uh we still have these Jagged edges here right now the way to fix that is again going here and increasing uh the detail amount in the icosahedron so if I increase this to 200 um you're not going to see those Jagged edges anymore right but this is gonna slow us down a bit uh when we want to reload the page so I'm going to turn this back at 100 alright so uh we're we're gonna get this Jagged Edge just but that's fine and we're gonna get these Jagged edges again but it's fine so uh let's come back here and uh let's take a look at this all right so we want to achieve this now um now decade 3D doesn't do anything a special after this point uh of course the lighting process is a bit different in blender so uh we need to achieve this section this Parts on our own all right so uh let's take a look at this and let's see what's the problem so um the first thing is we don't want to be displaying uh displaying the displacement values as the color that's that's the first problem because here the key 3D is using a solid color for all of this right so uh we're gonna come here and we're gonna set this to a solid color uh so let's use blue uh because why not so I'm gonna put these valleys like this and let's see what we will get uh with these values and we get a solid color but the problem is we don't have any Shadows we don't have any lighting we have nothing here right and that's that's very sad and boring right so the obvious thing here is that we're not going to write this whole fragment Shader uh for lighting and shadows uh today because that would take the whole day and um the way that we're gonna do this is we're gonna inject our own Shader code into 3GS materials and now I have a full video on this explaining this topic um so you should go ahead and watch that video first and if you already know how to do this uh let's just begin so I'm gonna come here and I'm gonna replace this with a standard material and this code will no longer work so let's just delete that uh underwear that we're going to be doing this is with the on before compile function so um before compile this gives us a Shader and we can store the Shader uh in the user data of the material again all of this is in my tutorial um on how to inject your shaders into three just materials so um we're gonna do that and I'm gonna copy this right here and instead of doing material uh those uniforms I'm gonna do Shader dots uniforms all right so this is storing a reference to the Shader object and this is uniforms alright so the way that we're going to be doing this uh is by first let's console.log the vertex here because most of our code happens in the vertex here so let's do Shader dot vertex Shader and let's see what we will get in the console uh so first uh we're gonna get this error of course in in here uh so now the way that we're going to be doing this is with material.userdata DOT Shader all right all right so now we get the string uh which is the vertex share and now uh we need to actually look for parsing uh vertex Shader and uh now we have to actually divide the vertex Shader that we have into two different parts one uh is the parse uh and one is the main um section so uh let's do the parsing one first let's copy this uh this include which has the displacement map uh parse vertex and we're going to come here and we're gonna say Shader dot vertex here um equals share dot vertexure dot replace and the way that we're going to be replacing this is we're going to come here and Define a parse vertex string so let's just paste that in and um let's do this paste this in and here if I add a comment uh if I add jlsl behind this and comment this with shift alt a I'm going to get syntax highlighting 4G LSL inside JavaScript and the way that you're gonna get that is with this extension uh called glsl literal all right so let's just type that in and since I accelerating for jealous all inside of JavaScript tagged template strings so you can download this and install it and uh if you add a comma like a comments like this before any Jello cell string it will it will add syntax elevating for you all right so uh here what I'm gonna do is I'm gonna use the replace and we're going to pass this in so parse vertex string and again I'm going to come here and what I'm going to do now is I'm gonna do use the same uh string so parse vertex strings but here I'm gonna add our own vertex Shader that we need so here I'm going to do vertex Shader um parse and we need to create a new file here in the shaders folder uh let's add vertex parse dot jlsl all right and what we're going to do here uh is we're going to copy all of these um all of these uniforms varying functions that are at the top of the main file all right so all of this code we're going to copy and we're going to paste it in here right so uh that's it we now need to import this uh section so we can come here and say import vertex horse Shader parts and from dot slash shaders vertex parse all right and let's change the name of this to vertex parse as well because that is Notch nicer and we need to Now define a Vertex main so vertex Main and we need to now create a file called vertex main so again in our shaders folder create a new file vertex main.gl cell and here we're going to copy and paste the contents of the main function of our vertex Shader and um you only need to copy up to this point um because the vertex Shader in 3GS already does this MVP calculation stuff so all you need to do is uh you need to copy this part right uh into the vertex main paste it here and now what we're going to do is very simple we're gonna come here in our app.js and uh we added this vertex Parts uh here and we still have this string and now uh you're gonna get an error here because you're redefining pi and V normal and stuff like that so uh what you can do is just uh come here and into the parse section and just delete this delete we normal uh Delete vuv the late position uh keep the displacement and due time and you also need to delete the Define pi because 3GS automatically defines pi and with that you're gonna get uh no errors right and here we can see our code that has been replaced but we're not going to care about that uh we're gonna come down here and find another displacement include which is now in the main function so we're going to copy this display some map vertex and here in app.js [Music] we're gonna create cost um main vertex string right and again the same thing we're going to create a literal uh template literal and paste that in and again the same thing needs to be applied here so share dot vertex Shader equals Shader let's actually close this because it's taking up space let's um continue so vertex Shader dot replace all right and we're going to use this main vertex string and again we're going to use this main vertex strings plus we now need to use the main vertex um thing that we have so here we need use the vertex parse here we need to use vertex main which is which comes from our file um so here if I go here um this comes from our file here right and with this everything should work fine so far uh let's see what error are we getting so we have a position Undeclared identifier all right um we have a vuv which is Undeclared and stuff like that so here in the main we need to actually delete these bearings that we had um because we only now need the V displacement let's also format this properly everything should work fine now yep we get no errors and now we need to actually displace uh the sphere right and here in vertex main.glassel we're going to modify this transformed variable now if you're interested in where this variable came from we can go into node modules scroll down to find three um so here three and open up the SRC folder open up renderers open up shaders and open up shaderchunk.js all right so uh we can close this now and if we search here for displacement this is the this is the file that we're actually replacing in 3DS um if we open this up displacement map vertex uh we're gonna get this code now this is very interesting because uh we can actually see how three just handles the displacement uh based on the displacement map right so we have this transformed and three just as uh this part to this transformed variable uh which uh which is very similar to what we wrote so we have the normalize uh object normal which is the normal of the object and we multiply that by the value that we're getting from the texture which makes sense and uh it has also other parameters but here you can see a structure that is very similar to our code so what we're going to do is we're going to use this transformed and uh this is a vek3 so we're gonna come here into vertex main.glsl and uh we're gonna add equals all right normal so we have the normal uh we can actually um actually in this vertex here it seems like three just is doing this so maybe we need to actually copy this and use it as the normal um so let's do that let's multiply this by um the displacement value and this should give us uh the displacement that we want right so yeah um this gives us a custom Shader that does the displacement for us so if I went a little bit too fast here uh here's the code that you actually need to be writing and the number four compile and in the material uh this is the actual code that you need to be writing and to access the Shader um you use the material uh user data right so very simple stuff uh I already explained all of this um in in my other tutorial about injecting your shears and now um this looks a little bit weird um and the reason for that is um we haven't actually done anything with the fragment here so if you take a look at this this not only has displacement but this object also has bump so it actually looks like that uh between the edges here we get some lighting effects and shadows and that is actually what bump does so we need to now go into um here and we need to modify our fragment here as a wall so what we can do here um is we can create two other files in the shears folder one should be fragments um main.jsl and the other one should be fragments parse Dot jlsl and this is how we handle things uh let's close these unnecessary um files here uh we're gonna need uh the Shader chunk file layer so let's keep that put it at the very end here and what we're gonna do is we're gonna look for um the displacement or bump um in in our fragment share so if you take a look uh we have this buff map parse fragment all right let's open that up um it's it defines some functions here all right so if you take a closer look at this a bump map parse fragment.j LSL file uh you're going to see we have uh two functions here and uh we have some references here also but um if we go back into Shader chunk.js and search for bump map or bump uh alone you're going to see we only have this bump Map Parts fragment in the entire file and what this means here is that these functions are being used in other files with other names so how can we find these functions um and where they're being used so you can select it and press Ctrl shift F and this is going to search for you in the entire repository and when you search for this uh you're gonna get this file which is the normal Maps uh fragment shooter so let's again close this and you can clearly see here how this is being used to uh to add the bump map right [Music] um so here we can copy this part into our fragment.glsl not this one but fragments main.gelic cell and now let's paste this in all right so we have this line of code and now let's inject this so if I come here and console.log Shader dot fragment shooter if we open up the console we're going to get our fragment share here all right and now we need to find the parts that this happens this normal fragment part so we need to copy the sports normal fragment Maps we come here let's search for that normal fragment Maps here it is let's copy that and let's go back into codeapp.js and what we're going to do is we're going to store this as a string so main fragments string equals jealous cell common this and with this you're gonna get this so that's it and let's do share dot fragment Shader equals share dot fragment Shader place and Main fragment string and we're gonna replace this with main fragment string Plus uh the file that we're going to be importing which will be uh fragments Main all right so let's define that at the very top here so we're going to do fragments Main and also a fragment parse right and let's change this to fragment all right and now uh what happens is well we need to actually Define this fragment Parts as well so if we come here and I can do the same thing for the parse associator Dot fragmentstreader equals share dot fragment Shader that's replace so let's go back here and see what we need to actually replace so what we want to replace this uh with is the bump map parse fragment so let's search for that um I think we have the string here so if I look through these bump map parse fragments we're going to find it here let's copy that and let's go to app.js Let's store this in const parse fragment string equals yellow cell comment this paste this in and parse fragment string all right and again here uh come down below parse fragment strings Plus parse or fragment parse and let's format this this is much nicer now so here we need to actually copy paste the parts from the fragment Trader um so going to fragment.j LSL and what we need to paste is we need to copy these two lines actually so only these two and uh we we can go to fragmentparts.jlsl paste this in and that should be it right this should work uh let's check the console nope all right so after 10 minutes of debugging this issue I realized that um here in app.js at the very top uh where we Define fragment parts we made a typo here so let's change this back to fragmentparts.jlsl and this fixes that issue but we still get an error here and I expect this error because uh let's look at what it's saying it says this function uh doesn't exist this function doesn't exist and the reason for this is if you take a look at a three Justice code here where we Define these functions uh it has an if def here and if def means if this um if this Define exists you can compile this code and this will be in the final compiled code right if this defined doesn't exist then you just don't don't Define this code right and so these two functions aren't actually defined but here's the problem the first problem is this function is using a bump map right so if we go above here we can see The Bump app being imported here now we don't have a bump map uh thing that we want to use as a bump map is our noise variable or or noise pattern okay so we don't need to import this function actually so uh the only thing we need here is uh we need this function only so let's copy this all right let's go into fragment.pars.glsl and here we can paste this in now uh let's format this as well so we can do this and we now need to use this all right so here in fragment main we're using this function which seems to create bumps and we're also using this function which I showed you which uses a bump map now if you take a look at the name of this function The Edge the X Y and if you take a look at the implementation uh this is actually calculating the derivative of a point based on um based on the height map or the bump map in this case right so uh that's what we're going to be doing but instead of having it an image uh as the above map we're going to be using our own noise variable right so uh here in the fragmentparts.glsl uh we don't have to do anything but uh here you can see we have this function here which I haven't really talked about DF DX and the fdy so uh these calculate the derivatives um in jlsl so I can come here and instead of having this I can delete this code and create a vic2 one I should be DF DX of or V displacement remember we're importing v-displacement as a varying here so we displacement and the other components should be DF d y of V displacement and uh this should work fine so let's reload the page and yeah we're getting something here and now this looks very weird um this looks like it has flat shading actually uh the problem here is we're actually calculating the bumps correctly but uh the issue here is that um we we don't have enough uh segments in in our sphere right so we can go into app digest and now we can increase the resolution to something like uh 300 detail and when we do that and reload the page we're gonna get this smooth result right and uh that's basically it that's the main section of this whole Shader and it nicely animates um now what you can do here is you can actually increase this even further uh make it 400 um and uh this will give you a much better result so the next part here that we need to implement is again if you take a look at this we have some nice coloring here so um we can actually do some coloring but I'm not going to do the coloring on the on the mesh or on the material what I'm going to do is I'm gonna do some lighting and we're going to do some post-processing to make this look cool so here in app.js I'm going to scroll up and here in the lighting section I'm gonna replace this part with some lights um and I'm going to change the color change the position of the light so uh I'm gonna give you a second to copy this part this is the lighting setup that we're going to be using and uh let's do some post processing now so at the top of the file I'm gonna import a post-processing pass which is the unreal balloon pass all right um so we're gonna scroll down now and uh here uh we're we can do some post processing and these are the passes from my boilerplate code uh we don't need them we can just remove them so we can do post processing and add pass this is a function in my template so add pass um and let's construct a new under your Bloom pass so I'm going to paste this in with some parameters and again you can have a look at this and copy this yourself um set the intensity to 0.7 here the radius to 0.4 and the threshold 2.4 and this will give you this final result now this is the final result which definitely looks cool now here are some adjustments which you can make to make this even look cooler so here at the timestamp I'm gonna remove one of the zeros to make this uh move faster and uh once we do that we get this animation now our uh noise function scale is kind of high so let's just go into our vertex Main and um here where we where we create the noise let's divide chords by 1.5 all right now another thing you can do to make this look even cooler is ADD you time uh to the to the inputs of the wave function here right so you can do that but uh this this will look a little bit too fast so what you need to do is go into app.js and maybe we can set this to 5000. and this will now give you our final result which looks very cool very organic and that's it for this crash course guys I hope you enjoyed this video of course there are many things that we could have covered uh in this video but don't worry there are going to be more videos coming out soon about cheers and uh big thanks to ducky3d for his amazing artwork definitely subscribe to his channel as well and I would like to thank Bruno Simon for his amazing 3GS Journey course and I definitely started out learning shares from his course um and I really hope that this tutorial has helped you um become much better at shaders and of course when your beginner shaders can be very hard to work with uh don't be discouraged um just keep going keep moving forward keep learning new things and um you know in some parts of this tutorial I might um I might have went a little bit too fast but uh I wanted to really show you guys what's the possibilities um behind behind cheers and how you can create really amazing stuff with shaders so that's going to be it for today thank you all very much for watching and on that note I'll see you guys next time
Info
Channel: Visionary 3D
Views: 16,086
Rating: undefined out of 5
Keywords: shader, glsl, dot product, threejs, threejs tutorial, shaders tutorial, glsl tutorial, three js course, three js course bruno simon, three js website, shaders, threejs shader, three.js, 3D, webgl, webgl tutorial, webgl shader, webgl course, shaders for beginners, threejs for beginners, shader animation threejs, 3D Graphics, bruno simon, bruno simon threejs, threejs journey, three js crash course, displacement, vertex, vertex shader, fragment shader, threejs shaders for beginners
Id: oKbCaj1J6EI
Channel Id: undefined
Length: 177min 28sec (10648 seconds)
Published: Sat Mar 18 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.