CS424 Notes, 22 February 2012
- Generated Texture Coordinates.
- If texture coordinates are not provided as part of a model, it might still be possible to apply a texture to the model using generated texture coordinates. One very simple idea would be to use the x and y object coordinates of a vertex as texture coordinates for that vertex. However, that does not work very well in general.
- Another option is cube mapping. The object
coordinates of a vertex have three components, x,
y, and z. Cube mapping uses two of the three
coordinates, and it decides which two to use based on
the general direction that the primitive is facing.
This can be checked by looking at the components of
the normal vector. The algorithm is something like:
let (x,y,z) be the object coordinates let (dx,dy,dz) be the normal vector if abs(dx) is larger than abs(y) and abs(z): if dx > 0 use (y,z) as the texture coordinates else use (z,y) as the texture coordinates else if abs(dy) is larger than abs(dx) and abs(dz) if (dy > 0) use (z,x) as the texture coordinates else use (x,z) as the texture coordinates else if (dz > 0) use (x,y) as the texture coordinates else use (y,x) as the texture coordinates
- The question is, when to do this. While it could be done in JavaScript, the most natural place is probably in the vertex shader.
- Other types of mapping are possible. "Tube mapping," for
example might, I think, compute the texture coordinates (s,t)
from the object coordinates (x,y,z) as:
t = y s = atan(x,z) / (2.0*pi)
In this case, the "tube" wraps around the y-axis. Furthermore, instead of object coordinates, you might use world coordinates or even window coordinates.
- Affine Transformations in 3D
- 3D has the same type of affine transforms as 2D: scaling, rotation, translation, and shear (although as in 2D, shear is not as important).
- Translation in 3D is similar to 2D, but now there are three coordinate directions. So a translation is given by three numbers (dx,dy,dz), giving the amount of motion in the x, y, and z directions. A value of 0 means no translation in that direction.
- Scaling also uses three numbers, (sx,sy,sz), to give the scaling factors in the x, y, and z directions. For uniform scaling, all three numbers are the same. A value of 1 means no scaling in that direction. A negative scaling factor implies a reflection. A scaling factor of 0 is bad, since it collapses an entire direction down to a single point. For example, scaling by (1,1,0) would map every point to a point in the xy-plane.
- Rotation introduces a new wrinkle: In 3D, you don't rotate about a point. Instead, you rotate around a line, which is called the axis of rotation. For example, the Earth rotates about a line that runs through the Earth's north and south pole. Ordinarily, the axis for a 3D rotation goes through the origin. (If you want an axis that goes through a different point, you can translate that point to the origin, rotate about a line through the origin, then translate back.)
- Suppose that you want to rotate about the line that goes through (0,0,0) and (a,b,c). There is still the question of which direction do you rotate for a positive angle? In 3D, you can't just say "clockwise" or "counterclockwise." The answer is given by the right-hand rule: Point your thumb in the direction from (0,0,0) to (a,b,c), and your fingers will curl in the direction of rotation for a positive rotation.
- Rotations about the x-axis, about the y-axis, and about the z-axis are common, but rotations about other axes are also useful.
- Matrices for 3D
- Equations for an affine transform applied to (x,y,z) have
the form
xnew = a * xold + d * xold + g * xold + j; xnew = b * xold + e * xold + h * xold + k; xnew = c * xold + f * xold + i * xold + m;
where all coefficients are constants. - Just as an affine transform in 2D can be expressed as a 3-by-3 matrix, an affine transform in 3D can be expressed as a 4-by-4 matrix. The bottom row of the matrix is (0,0,0,1). To transform (x,y,z), multiply (x,y,z,1) by the matrix, and discard the final coordinate to get the new (x,y,z).
- Equations for an affine transform applied to (x,y,z) have
the form
- The JavaScript library gl-matrix.js
- To work in JavaScript with transformations in 3D, we will rely on the JavaScript library gl-matrix.js, a redistributable open source library written by Brandon Jones. This library implements operations on 3D vectors, 3-by-3 matrices, and 4-by-4 matrices, in a way that would be familiar to OpenGL programmers
- gl-matrix.js is not object oriented. For this library, a vector is just an array of three numbers. It can be either a built-in JavaScript array or a Float32Array. A 3-by-3 matrix is an array of nine numbers, giving the matrix in the column-major order that is required for WebGL. And a 4-by-4 matrix is an array of 16 numbers, giving the matrix in column-major order. Note in particular that matrices are implemented as one-dimensional arrays, not two-dimensional arrays. These matrices can be used directly in the functions gl.uniformMatrix3fv and gl.uniformMatrix4fv to set the values of uniform matrix variables in a shader program.
- gl-matrix.js defines three "objects" vec3, mat3, and mat4 but they are not objects in the sense of object oriented programming. In Java, they would just be classes that contain a bunch of static methods, like the Math class. For example, mat4 is a collection of functions for operating on 4-by-4 matrices, where each matrix is implement as an array of 16 numbers. For example, mat4.translate(matrix,[2,3,-1]) modifies matrix by multiplying it on the right by a translation, where the vector [2,3,-1] gives the translation amounts in the x, y, and z directions. In particular, note that mat4 is not a matrix! The matrix that is being operated on is passed as the first parameter to the function.
- Here is an example of using mat4 to make a transformation
matrix representing a scale, followed by a rotation, followed by
a translation:
var modelView = mat4.create(); mat4.identity(modelView); // Set to identity mat4.translate(modelView, [0, 0, -10]); // Translate back 10 units mat4.rotate(modelView, Math.PI/2, [0, 1, 0]); // Rotate 90 degrees around the Y axis mat4.scale(modelView, [2, 2, 2]); // Scale by 200%
This example is taken directly from the library's web site. Note that mat4.create() makes a new matrix. You could also create it with new Array(16), but mat4.create() makes a Float32Array, which is more efficient and better adapted to WebGL. - What should we do about the stack of transformations that is needed to implement hierarchical graphics.