-
-
Save ds604/612318540f1bba523a7d111205b55098 to your computer and use it in GitHub Desktop.
Annotated WebGL sample.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
We're going to start by adding a canvas to the page and getting a context for it. | |
*/ | |
var canvas = document.createElement("canvas"); | |
canvas.width = canvas.height = 320; | |
document.body.appendChild(canvas); | |
var gl = canvas.getContext("experimental-webgl"); | |
/* | |
WebGL doesn't know how to draw anything onscreen out of the box. We have to | |
teach it via shaders--programs that set the coordinates of polygon corners | |
(vertex) and set the color for each pixel inside (fragment). | |
Shaders are written in a C-like language named GLSL. We'll set up the source | |
code in a set of strings, then compile the shaders. | |
*/ | |
var vertexSource = | |
//declare variables that we'll pass in from JavaScript | |
"attribute vec2 a_position;" + | |
"attribute vec3 a_color;" + | |
"varying vec3 v_color;" + | |
//main() is the entry point to the shader | |
"void main() {" + | |
//gl_Position is the final vertex position in screen-space, which | |
//ranges from -1 to 1. It's basically x, y, z, w, the latter two | |
//you don't need to worry about for 2D. | |
"gl_Position = vec4(a_position, 1, 1);" + | |
//Pass the color in to the fragment shader from the attribute | |
"v_color = a_color;" + | |
"}"; | |
var vertex = gl.createShader(gl.VERTEX_SHADER); | |
//plug the source into the new shader and compile it | |
gl.shaderSource(vertex, vertexSource); | |
gl.compileShader(vertex); | |
//if something goes wrong, we can ask for the info log for each shader | |
console.log( gl.getShaderInfoLog(vertex) ); | |
var fragmentSource = | |
//precision is required, but mediump is fine as a default | |
"precision mediump float;" + | |
"varying vec3 v_color;" + | |
"void main() {" + | |
//The fragment shader is easier: we just set the pixel color directly. | |
//we'll add the alpha as the fourth component | |
"gl_FragColor = vec4(v_color.r, v_color.g, v_color.b, 1);" + | |
"}"; | |
var fragment = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource(fragment, fragmentSource); | |
gl.compileShader(fragment); | |
/* | |
A GL program is the combination of vertex and fragment shader used to | |
draw shapes onscreen. We take our compiled shaders, attach them to the program, | |
link it all together, then tell WebGL that this is the program we want to use. | |
Later on, you can make different programs and switch between them, depending on | |
what you're drawing, but for right now we'll stick to one. | |
*/ | |
var program = gl.createProgram(); | |
gl.attachShader(program, vertex); | |
gl.attachShader(program, fragment); | |
gl.linkProgram(program); | |
gl.useProgram(program); | |
/* | |
There are three kinds of variables in GLSL: | |
- uniform: gets passed in to both fragments and vertexes | |
- attribute: gets passed in to the vertex shader as an array of values | |
- varying: set from the vertex shader, used in the fragment shader | |
We don't use uniforms in this sample, but they're pretty simple. Let's set up | |
an array of attribute values, for the corners and colors of a triangle. | |
*/ | |
//create the empty buffer | |
var buffer = gl.createBuffer(); | |
var bufferData = [ | |
//structured as x, y, r, g, b | |
0, 0.5, 1, 0, 0, //top corner, red | |
-0.5, -.3, 0, 1, 0, //left corner, green | |
0.5, -0.3, 0, 0, 1 //right corner, blue | |
]; | |
//tell WebGL that the next command applies to the buffer we created. | |
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); | |
//fill the buffer with our data (converted to a Float32Array) | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(bufferData), gl.STATIC_DRAW); | |
//STATIC_DRAW sets WebGL to optimize for drawing from this data once | |
/* | |
Now we want to tell the WebGL context how to interpret our buffer, which is | |
organized as two coordinate values followed by three color values. We're still | |
bound to the buffer, so we'll ask WebGL for the ID of each attribute we used in | |
the vertex shader, then declare their position in the array. | |
*/ | |
//get the id for the a_position variable | |
var a_position = gl.getAttribLocation(program, "a_position"); | |
//Why do we have to enable it? It's complicated, but we do. | |
gl.enableVertexAttribArray(a_position); | |
//declare its position in the buffer (see below) | |
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 20, 0); | |
/* | |
The arguments for gl.vertexAttribPointer() are as follows: | |
- the variable id that we got from gl.getAttribLocation() | |
- the size of the variable (a_position is a vec2, meaning an array of 2 values) | |
- the type of the variable. Most GL values are FLOATs | |
- whether the value is normalized. Assume this is false for now. | |
- the distance between values--in this case, each vertex gets 5 floats, each | |
of which is 4 bytes. So our "stride" is 20 bytes from one coordinate pair to | |
the next. | |
- how far the value is offset from the start of the array--in this case, 0. | |
*/ | |
//get the next variable id | |
var a_color = gl.getAttribLocation(program, "a_color"); | |
gl.enableVertexAttribArray(a_color); | |
gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 20, 8); | |
/* | |
In the case of the color, the stride is the same--20 bytes between each set of | |
values--but the color values start after 8 bytes (2 floats) of coordinates. | |
Finally, we'll draw our polygon by calling gl.drawArrays. We're going to draw | |
a triangle onscreen. Most of the time, WebGL wants us to draw triangles because | |
they're unambiguous--there's only one possible polygon they could be. If we | |
want a rectangle, we have to draw two triangles. | |
*/ | |
//draw triangles, starting at location 0 and proceeding for three vertices | |
gl.drawArrays(gl.TRIANGLES, 0, 3); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment