In this lesson we cover how to pass data into a WebGL shader from the main JavaScript program.
[00:01] Going over shaders a bit, and seeing how the code in shaders effects what is drawn to the screen, but we don't really want to be hardcoding colors and vertex positions in our shaders, because generally the shaders are going to be compiled once and used for the rest of the program. There's no real easy way to change them on the fly other than writing a new one and recompiling it. Ideally your shaders are dynamic programs that act on data passed into them from the main program.
[00:28] So let's look at how to pass data to the shaders. Looking back at our vertex shader here, we're hard coding the value of gl-position, by creating a vec4 with specific coordinates. We need a way to use a variable here. We want to be able to say like this, gl-position = coords. We'll do this with a special kind of webgl variable called an attribute. Up at the top of the shader outside of the main function we simply say attribute vec4 coords.
[01:03] The fact that we define this as an attribute of the program allows us to find the location of this attribute from our main program and pass data into it. Whatever data we pass into it, will be assigned to gl-position, make sense? Now that we've set up the shader, we need to know how to find that attribute from the main program. There's some special webgl methods that will help us out with that. I'll call and create a new function called createVertices. To get that location of that coords attribute, I'll call the webgl method gl-getAttributeLocation.
[01:39] This will need to know the shader program that we're using, and the name of the attribute. I'll store that in a variable called coords. We can now use that attribute location to pass data to the attribute which will then be used in the shader. Now there are a bunch of methods for passing data to attributes. We'll use gl-vertexAttrib3f. This allows us to pass in three floating point values to an attribute, which will generally be used to hold vertex information. It gets passed the attribute location and the three values.
[02:18] We'll say 000Run that, and we're still back at center. I'll just change some of the coordinates here, yep, that works. Now you may have noticed that we defined the coords attribute as a vec4, but we're only passing in three values. Webgl will notice that you're assigning vertex data but have only supplied three values, and will supply that fourth w value as 1 automatically. Now we can do the same thing for point size as well.
[02:52] We'll create another attribute, this will simply be a float, attribute float pointsize, and we'll assign that to gl-pointSize instead of hardcoding it. Back in the main program in createVertices, get the location of the pointSize attribute in the same way we get the coords attribute. This time, though, we only want to pass in a single value so we'll use gl-vertexAttribute1f pointSize 10, and our pointSize has been set. I'll try a couple different values just to make sure.
[03:29] The obvious next step is to do the same thing with color. Fragment shaders get a bit more complex though, first of all we need to use a different kind of variable. This one is called a uniform. One of the key things about an attribute is that the value can be different for every single vertex if you're using an array of vertices. We'll see that in action later, but fragment shaders aren't addressing vertices, so an attribute doesn't make sense here. A uniform, however, is a variable that will be the same each time the shader is called.
[04:05] So we say uniform vec4 color, simple enough. But fragment shaders are also a bit more fussy about datatypes. If we use floating point values, which we are here, we need to let the shader know what level of precision will be used for those values. We'll do that with a line that says precision medium P float. This tells the shader that it should be using a medium precision floating point value, which is fine for what we're doing here. Now we just assign color to gl-fragColor.
[04:42] Back in the main program, we need to get the uniform location, and I bet you can already guess how I'm going to do that, gl-uniformLocation shader program color. Now to pass data to uniform there are more special methods. For four values we'll use gl-uniform4f, passing in the uniform location and the four values. Now our shaders have nothing hardcoded, we can use them to set any vertex position, point size, and color, all from the main program.