CS 424: Computer Graphics, Spring 2012
Lab 4: Textures and Point Sprites
In this lab, you will be applying textures to points and primitives. Some of the work will involve working on shader programs. To begin the lab, create a project folder named lab4, and copy all the files from /classes/cs424/lab4-files into your project folder. You will be working on points.html and textures.html.
Exercise 1: Textured Points
The program points-example.html shows a bunch of red dots moving around in the canvas, bouncing off the edges. The dots are in fact a single primitive of type gl.POINTS. The first exercise of the lab is to modify points.html so that an image texture will be applied to the points. Click here to see a picture of this using my WebGL logo image as the texture. In the picture, I have also doubled the point size. (Note that points are square, but I want circular dots so I discard pixels outside the circle.)
To do the exercise, you will have to add a uniform variable of type sampler2D to the fragment shader to represent the texture, and use the sampler to get the color of the fragment. You should use gl.uniform1i to set the value of the sampler2D to 0 (zero), meaning that the texture will come from texture unit 0. (You should also do gl.activeTexture(gl.TEXTURE0); this is the default and should not be necessary, but at this time Safari seems to require it for textures to work properly.) And you will have to load the texture image. We have looked at an example in class, and there is an example in texture-coords-example.html.
Exercise 2: Applying Texture Images
The program textures.html shows a gray rectangle. Beneath the canvas are three groups of controls, but currently the first group is the only one that does anything. Changing the values of R, G, and B will change the color of the rectangle. The two groups of radio buttons should control how two textures are applied to the rectangle. The textures that you should use are earth.jpg (from planetpixelemporium.com) and bricks-with-alpha.png. (The second image shows some bricks, but I've added an alpha component that varies from point to point. This would not normally be very useful; it's done here just to give you an alpha component to work with as an example.)
You should load the first of the two images into texture unit 0 and the second into texture unit 1. (Recall that you can use gl.activeTexture(gl.TEXTURE0) when working on texture unit 0 and gl.activeTexture(gl.TEXTURE1) when working on texture unit 1.) You will have to write another loadTexture function to load the texture images.
A texture image is "sampled" to produce a color for each fragment. That texture color must be used in some way -- that is, to set or modify the color of the fragment. In this case, the fragment's color should start out as the base color of the rectangle. The first texture, if it is used, will replace or modify that base color, giving a new color for the fragment. The second texture, if it is used, will also replace or modify the color. Note that if both textures are used, and the second texture color simply replaces the previous fragment color, then you won't see any effect at all from the first texture (or the base color).
I'd like you to implement 7 ways of using a texture. In the program, I call this the "mode" of the texture. The seven modes are given by constants 0 through 6. I've given the constants names to make them easier to remember:
- NO_TEXTURE (0) -- Don't use the texture at all.
- TEXTURE_REPLACE (1) -- Replace the RGB components of the current fragment color with the RGB components of the texture color.
- TEXTURE_MULTIPLY (2) -- Multiply each of the RGB components of the current fragment color with the corresponding components of the texture color.
- TEXTURE_ADD (3) -- Add each of the RGB components of the texture color to the corresponding components of the current fragment color.
- TEXTURE_SUBTRACT (4) -- Subtract each of the RGB components of the texture color from the corresponding components of the current fragment color.
- TEXTURE_BLEND_50_50 (5) -- Set each of the RGB components of the fragment color to be the average of the fragment color component and the texture color component.
- TEXTURE_BLEND_ALPHA (6) -- Set each component of the fragment color to be a mixture of the fragment color component and the texture color component, where the mix is given by the alpha component of the texture color. For example, if the alpha component is a and the two R component values are R1 and R2, then the new color is computed as R1*(1-alpha)+R2*alpha. This mode is not available for the first texture, since that texture image has no transparency.
Note that in most cases, I don't want you to change the alpha component of the previous fragment color. There is a good use for swizzlers here. If you just want to change the RGB components of a vec4, color, you can assign a value to the vec3, color.rgb. For example, to divide the RGB components by 2, you could say color.rgb = color.rgb/2.0.
The second exercise of the lab is to implement textures in textures.html and to make the radio buttons work. You will need two uniform sampler variables in the fragment shader, one to represent each texture. (The values of these uniforms should be set to 0 and 1 in the JavaScript program.) You will also need two uniform variables of type int in the fragment shader to represent the mode to use for the texture. You'll need to add a fair amount of code to the fragment shader to implement all the different modes for both textures. (Be sure to set the values of the int and sampler uniforms using gl.uniform1i. When I accidentally used gl.uniform1f instead, it took me over an hour to find the problem.)