CS 424: Computer Graphics, Fall 2015
Lab 12: WebGL 3D and gl-matrix
In this lab, you will work with procedural textures and texture transformations in WebGL. The procedural textures will be implemented in a GLSL fragment shader. The texture transformations will use the vector and matrix math library gl-matrix.js.
You will need a copy of the folder lab12-files from /classes/cs424. The starting point for the lab is the file lab12.html, which already implements a couple of procedural textures. The other files in the folder are scripts that are used by that file. You will only work on lab12.html. The program is based on the demo procedural-textures.html from Section 7.3.3
This lab is due in two weeks, on Thursday, December 2. You can turn in either your copy of lab12.html or the entire lab12 folder.
The file lab12.html already has input boxes for numbers. The numbers represent a texture transformation that should be applied to the texture coordinates before they are used to sample the texture. (The values of rotateX, rotateY, and rotateZ are meant to represent three rotations, about the x-, y-, and z-axes.) There is an "Apply Transform" button that calls the function applyTextureTransform(). That function currently just gets the nine numbers out of the input boxes and puts them into an array named values. As it stands, nothing is done with the numbers.
Your task is to implement the texture transform. You will need another matrix of type mat4 in the shader program, and you will need to use functions from gl-matrix.js to create the matrix. The actual transformation must be applied to the 3D texture coordinates in the fragment shader. (Currently, there is effectively a hard-coded texture transformation that scales the texture coordinates by 5. Without this scaling, the texture would only repeat once on the objects used in this program.)
About 3D Procedural Textures
You have used procedural textures, such as marble and clouds, in Blender. In a procedural texture, the texture color is computed, based on texture coordinates, rather than sampled from an image. For a 3D procedural texture, there are three texture coordinates, (s,t,r), instead of two. Typically, object coordinates are used as texture coordinates, though they can of course be subject to a texture transformation. A 3D texture is a pattern in three-dimensional space. When it is applied to an object, it is as if the object is "carved" out of that pattern.
The original lab12.html has three procedural textures: a checkerboard texture, a cloud texture, and a marble texture. For clouds and marble, some kind of pseudo-randomness is needed. A common kind of pseudo-randomness for 3D textures is Perlin noise. The cloud texture is pure Perlin noise. For the marble texture, the Perlin noise is used to perturb a periodic function. In the program, Perlin noise is implemented by an open-source GLSL function. (No, I don't understand how it works.)
Implementing the textures
The second part of the assignment is to add several new procedural textures. You should add new entries in the pop-up menu that selects the texture, and you should add code to the fragment shader to implement the textures. Here are some examples:
At least one of the new textures should not use Perlin noise. It should be some regular pattern, like the checkboard. (Consider making the color components depend on sine functions, which are periodic. Sine functions were used to make the multi-colored texture on the left above. Another type of periodic function is f(t) = t − floor(t), which is used in two of the examples in the demo.)
At least two of the new textures should use Perlin noise. They should not be simple variations on the textures that are already defined. One option is to use Perlin noise as the basis for the pattern, but to use only a limited number of colors, depending on the noise value. (Perlin noise has a value between -1.0 and 1.0.) The "cow" texture and the "camo" texture in the illustration were made using this technique.
However, one of your two noise textures should be created by using the noise to perturb a regular pattern. For example, the "wood" texture on the right above used a basic idea of making rings by using a sine function of the distance of texCoords.xy from 0.0. (I had to multiply the distance by a fairly large value to get the rings to be a reasonable size. And it probably would have worked better to use a function based on f(t) = t − floor(t).) But the rings were modified by adding a multiple of the noise function to the argument of the sine function (similarly to what was done for the marble texture). If you look closely, you will notice that the wood also has a subtler fine grain. This was created by adding a dark brown multiplied by a multiple of a noise function, where the noise function was evaluated at vec3(texCoords.x, texCoords.y*32.0, texCoords.z). Multiplying texCoords.y by 32 has the effect of greatly compressing the noise in the y-direction.