CS 424: Computer Graphics, Fall 2015
Lab 11: WebGL 2D and GLSL
This is our first lab using WebGL and GLSL. For now, we will stick to 2D. (In fact, the program that you will work on would really make more sense in the canvas 2D graphics API than in WebGL.) The starting point for the lab is lab11.html, which is the only file that you will need today. You can find a copy in /classes/cs424.
This lab is due next Thursday, November 19. You should turn in your copy of lab11.html.
Color Attribute
The program in lab11.html currently shows a number of moving red squares that bounce off the edges of the canvas. The canvas fills the entire content area of the web browser. The squares also respond to the mouse: If you left-click or left-click-and-drag on the canvas, all of the square will head towards the position of the mouse. If you shift-left-click, the data for the points is reinitialized, so they start back at the center.
Currently all the squares are red. The first exercise is to allow the possibility of random color. The squares, in fact, are all part of a single primitive of type gl.POINTS. To assign different colors to the squares, you need to use an attribute variable. Your first task is to add a color attribute variable of type vec4 to the vertex shader, and use the values of the attribute to color the squares. You can create random values for the colors. Note that you will also need a varying variable to get the value of the color attribute from the vertex shader to the fragment shader.
After you get multi-colored squares working, you should make the colors optional. You can turn the use of the attribute value array on and off using the following commands, where a_color_loc is the id for the color attribute in the shader program:
gl.enableVertexAttribArray(a_color_loc); gl.disableVertexAttribArray(a_color_loc);
When the attribute array is enabled, each vertex gets its own color, from the attribute's buffer. When the attribute array is disabled, all vertices get the same color, and that value is one that was set using the gl.vertexAttrib* family of functions. For example, to set the value to be used when the color attribute array is disabled, you can use
gl.vertexAttrib3f(a_color_loc, 1, 0, 0); // set attrbute color to red
Let the user hit the space bar (or some other specific key) to turn the random colors on and off. The program has a doKey() function that is already set up to respond to keyboard input. You will be adding several types of keyboard interaction to the program. To respond to a key, you need to know the numeric keycode for that key. For the space bar, the key code is 32. The doKey() function outputs the keycode to the console every time the user hits a key, and you can use that feature to discover any other keycodes that you need later in the lab.
(Note: You should document the functions of the various keys that are used by your program in a comment at the top of the script.)
Point Style
Square points are boring. You should add the option of using different display styles for the points. Let the user select the style using the keyboard; for example, by hitting number keys.
Add a uniform variable of type int to the fragment shader to control the point style, and add code to the fragment shader to implement the various styles. The basic square should be one possible style. You can also color the square more creatively, for example with a gradient that varies from white to the point color. Some of the styles should be disks instead of squares. We saw in class how to draw a point as a disk by discarding some pixels:
float dist = distance( vec2(0.5), gl_PointCoord ); if (dist > 0.5) { discard; }
You should also make use of alpha transparency in some of your styles. To enable use of the alpha component, you need to add the following lines to the function's initGL():
gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
With these settings, the alpha value of a color will be used for transparency in the usual way. In particular, one of your styles should show a point as a disk that fades from fully opaque at the center to transparent at the edge.
Other ideas include using a radial gradient on a disk or just drawing a ring (by discarding pixels except in a small range of values of dist). Be creative!
Line Primitive
To add some visual interest, make it possible to draw line segments connecting each point to the next. In fact, you can draw all the lines as a single primitive of type gl.LINE_LOOP, using the same vertices as are used for the gl.POINTS primitive. The only difficulty is that the fragment shader will need to know whether it is drawing a point primitive or a line primitive (since gl_PointCoord is not defined for a line primitive, so all the code that you just wrote for point styles won't make sense for lines). (Another option would be to use another shader program for drawing the lines, but that would be overkill for this little program.)
Note that line width can be set by calling gl.lineWidth(w), where the width, w, is given in pixels.
You should make the lines optional. Provide some keyboard control for turning them on and off. You can make the lines a uniform color, or let them take their color from the same vertex attribute that is used by the points. Better yet, let the user choose.
It will look better if you draw the lines before you draw the points.