In this lesson we cover how to pass an entire array of 3d points to a vertex shader, allowing you to render multiple points at once.
So far, we've been passing in a single vertex to our shaders to be rendered as a point. If that's all WebGL could do, we'd be pretty boring. In order to start building up interesting forms, we need to be able to pass multiple vertices.
We do that with vertex buffers. A vertex buffer is an array of vertices stored in memory on the GPU. Because it's already there where WebGL is running, it's very fast and efficient. We need to know how to create a vertex buffer, how to get data into it, and how to pass that to our vertex shader.
I'll add a new variable called vertices to the top of the file, so we can access it in various parts of the program. In createVertices, I'll create an array. Before I add any numbers, let's look at the coordinate system we'll be using.
As opposed to 2D canvas in HTML, WebGL uses a more traditional Cartesian coordinate system. By default, the origins, or zero, will be at the center of the viewport. Minus one X on the left edge, plus one on the right, minus one Y on the bottom, and plus one on the top.
We'll be making a triangle like this, so the points will be -0.9, -0.9, +0.9, -.9, and 0, +0.9. Actually, though, remember that we're in 3D here. Each vertex will actually have a Z value as well, which we'll leave for zero as now.
In WebGL, plus Z extends toward the viewer, and minus Z, away into the distance. The vertex array will be a simple one-dimensional array holding a list of raw numbers. Later, we'll tell WebGL how to interpret this.
We won't be accessing this buffer directly. What we'll be doing is binding it to a target by saying gl.bindBuffer, gl.ARRAY_BUFFER, buffer. Binding, in this case, means that you're setting this buffer as the target of future WebGL buffer operations.
There are different types of buffers. There are different types of buffer targets. We're using the array buffer target, hence the first argument, gl.ARRAY_BUFFER. Any time WebGL needs to perform an action on an array buffer, it will look to see what buffer is bound to that array buffer target, and use that.
The first operation we'll do on that buffer is to put our vertex data into it with gl.bufferData. Again, gl.ARRAY_BUFFER tells WebGL the target buffer to use for this data. There's the data itself, which we'll wrap in a special data structure, a Float32Array.
This is simply an array of 32-bit floating point values. The STATIC_DRAW parameter tells WebGL how we intend to use the data. This option says that we'll use the values often, but we won't be changing them much.
There are other options for other use cases, such as data that will change more often. We have a vertex buffer that now has our vertex data in it. We need to assign it to the coords attribute so the shader can use it.
Previously, when we were assigning a single vertex to a coords, we used the gl.vertexAttrib3f method, passing in the three values. Since we have an entire buffer full of data, we need to do things a bit differently.
We need to pass a pointer to that buffer. We'll do that by calling gl.vertexAttribPointer. First is the coords attribute location. WebGL knows at this point that it's going to use the currently-bound array buffer. We don't need to specify that.
We do need to give it some info about what's in that buffer. We need to tell it that each vertex will have three values -- X, Y, Z -- and that they will be floating point numbers. The last three arguments, we'll cover later.
They'll allow for more complex buffers to be passed, and will let you specify how the data in those buffers is to be interpreted. Finally, we call gl.enableVertexAttribArray coords, which enables that particular vertex buffer object.
We're done using this vertex buffer, so we can unbind it. We do that by calling gl.bindBuffer again with gl.ARRAY_BUFFER, but passing in null. We've now got our vertices encoded, and we're ready to draw them.
By passing in a vertex buffer with an array of vertices, our vertex shader will be called multiple times, once for every vertex in that buffer. Each time, the coords attribute will get the value of the current vertex, and our shader will assign that vertex to gl_Position.
We can jump down to the draw function, and we already have our drawArrays method being called. Right now, we're saying that we only want to draw a single point with that last argument. We'll change that to three to reflect the fact that we now have three points.
Yes, we have three points being drawn. Try changing the values in the vertices array, and see the points appear in new locations. Verify that the point size and color values still work on these new points.
Try adding another vertex or more to the list. If you do that, don't forget to change the value drawArrays to reflect the new number of vertices.