Syllabus Blank Homework Quizzes Notes Labs Scores Blank

Lecture Notes
Dr. Tong Lai Yu, 2010
 1. Introduction 2. OpenGL Shading Language ( GLSL ) I 3. GLSL II 4. Curve and Surface Design
 5. Modeling Shapes with Polygonal Meshes 6. Texture Mapping 7. Casting Shadows 8. Tools for Raster Display 9. Parsing External Objects

Texture Mapping

1. Mapping Methods

Apply discrete data for surface rendering

Three major techniques:

• Texture mapping -- uses a pattern ( or texture ) to determine the color of a fragment. Can be 1, 2, 3, or 4 dimensional.

• Bump mapping -- distorts the normal vectors during shading process to make the surface appear to have small variations in shape like the bumps on a real orange.
 Sphere without bump mapping. Bump map Sphere with bump map resembling an orange

• Environment mapping ( reflection mapping ) -- the texture is used to store the image of the environment surrounding the rendered object. Examples:
2. Two Dimensional Texture Mapping

• Texels -- texture elements

• Texture coordinates -- s, t

• Texture pattern T(s, t)

• A Texture map associates a texel with each point on a geometric object that is itself mapped to screen coordinates for display.

• If homogeneous coordinates (x, y, z, w) are used, then
x = x(s, t)
y = y(s, t)
z = z(s, t)
w = w(s, t)

• Given a point (x, y, z, w), inverse functions give texel T(s,t):
s = s(x, y, z, w)
t = t(x, y, z, w)

• For parametric (u, v) surfaces, we need an additional function to map from (u, v) to (x, y, z, w). We also need the mapping from (u, v) to (s, t) and its inverse.

• Parametric surface:

• Linear-mapping a point on texture T(s,t) to a point on p(u,v):
u = as + bt + c
v = ds + et + f
The mapping is invertible if ae ≠ bd.

• Linear mapping makes it easy to map a texture to a group of parametric surface patches.

• Example: For a surface of revolution,

p(u, v) = ( r(u) cos(v), r(u) sin(v), h(u))

0 ≤ u ≤ 1 and 0 ≤ v ≤ 2π , then
s = u, and t = v / 2π

3. Assigning Texture Coordinates

To apply texture maps to an arbitrary surface, it is convenient to define the surface parametrically by a function p(u, v).

Example: Map a texture onto the side of a cylinder ( excluding the top and bottom sides ) :

• Cylinder's side surface:
p(θ,y) = (r sin θ, r cos θ )

Here (u, v) = (θ, y)

• y : -h/2 to h/2

• Assigning texture coordinates:
• s = θ / 2π,
• t = ( y + h/2 ) / h

So s varies from 0 to 1 as θ changes from 0 to 2π,
t varies from 0 to 1 as y changes from -h/2 to h/2

Example:Map texture to sphere

• Define the sphere parametrically:
p( θ , φ ) = ( r sin θ cos φ, r sin θ sin φ, r cos θ )
where
• θ = angle from z-axis ( 0 ≤ θ ≤ π ),
• φ = angle from x-axis ( 0 ≤ φ ≤ 2π )

• Assigning texture coordinates:
• s = φ/2π
• t = θ/π

• Given a point (x, y, z), we can obtain (s, t) :
• t = cos-1 ( z / r ) / π
• s = cos-1( x / r sin ( t π ) ) / 2 π

 ```#define PI 3.141592654 #define TWOPI 6.283185308 void SphereMap( double x, double y, double z, double radius, double *s, double *t) { *t = acos(z/radius) / PI; if (y >= 0) *s = acos(x/(radius * sin(PI*(*t)))) / TWOPI; else *s = (PI + acos(x/(radius * sin(PI*(*t))))) / TWOPI; } ```

• The exact north and south poles of the sphere, each of which needs to be "spread" out along the whole edge t=0 and t=1. In the formula above this is where sin(t π) = 0.

• The whole line at North Pole and South Pole texture map to a single point at the poles.

4. Mipmapping and Antialiasing

• Mipmaps are images for increasing rendering speed and minimizing aliasing effects.

• Texture mapping using point sampling often causes aliasing.

e.g. miss blue stripes
• A better but slower option is to use area averaging but
Curved preimage may occur when we project a pixel backward.

• Interpolating texture map pixels can smooth out rugged features.

• Mipmapping is a common technique to smooth out texture maps.

• Mip ~ many in one

• Precompute a family of lower resolution texture maps and display one with resolution best matches that of the screen

• Assume texture map of dimension M x N, where M and N are powers of 2.

• Map of reduced resolution (M/2) x (N/2) is obtained by averaging four pixel values

• Recursively apply the process to obtain maps with arbitrarily low resolution

• When view closer, use high resolution maps, and when view from a distance, use low resolution

• The memory used by successive mipmaps is
1 + 1/4 + 1/16 + 1/64 + .... = 4/3

• Controlling Filtering
 Mapping texels to pixels. (a)Magnification. (b) Minification. In both cases, the fastest strategy is to use the value of the nearest point sampling.

e.g. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

5. Texture Mapping an Image with OpenGL

Texture mapping -- applying a graphics image, a picutre, or a pattern to a surface.

Properties of texture maps:

• a texture map can apply an actual picture to a surface such as a label on a can or a picture on a billboard or can apply semirepetitive patterns such as wood grain or stone surfaces

• more generally, a texture map can hold any kind of information that affects the appearance of a surface

• can be done by table look up; the individual values in a texture array are often called texels

• used often in real-time rendering settings such as games to reduce computational load

• can hold colors that are applied to a surface to overwrite current color of objects ( in this case no lightling calculations should be performed )

• can hold attributes such as color, brightness, or transparency to blend with existing colors

• can hold attributes such as reflectivity coefficients, normal displacements or other parameters in the lighting model

Steps in Texture Mapping:

• Enable Texture Mapping:

glEnable ( GL_TEXTURE_1D );
glEnable ( GL_TEXTURE_2D );
glDisable ( GL_TEXTURE_1D );
glDisable ( GL_TEXTURE_2D );

• Create a Texture Object and Specify a Texture for That Object:

data describing a texture may consist of one, two, three, or four elements per texel, representing anything from a modulation constant to an (R, G, B, A) quadruple.

e.g.

GLuint handles[2];
glGenTextures(2, handles);

glBindTexture(GL_TEXTURE_2D, handles[0]);
// Initialize texture parameters and load a texture with glTexImage2D

glBindTexture(GL_TEXTURE_2D, handles[1]);
// Initialize texture parameters and load another texture

• Indicate How the Texture Is to Be Applied to Each Pixel:

You can choose any of four possible functions for computing the final RGBA value from the fragment color and the texture-image data:
1. decal mode -- the texture color is the final color; the texture is painted on top of the fragment ( Demo ... )
2. replace mode -- a variant of the decal mode
3. modulate mode -- use texture to modulate or scale the fragment's color; this technique is useful for combining the effects of lighting with texturing
4. constant mode -- a constant color is blended with that of the fragment, based on the texture value

e.g. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

• Draw the Scene, Supplying Both Texture and Geometric Coordinates:

Need to specify both texture coordinates and geometric coordinates .
e.g. 2-D textural map,
texture coordinates: [0.0, 1.0]
object coordinates: anything
e.g. brick wall, we can assign texture coordinates
(0,0), (1,0), (1,1), (0,1)
We must also indicate how texture coordinates outside the range [0.0,1.0] should be treated.

• Delete the texture from memory when it is no longer used:

glDeleteTextures(2, handles);

Texture Names:

To start things off, we first need a texture name. This is essentially a number that OpenGL uses to index all the different textures.

```GLuint texture;

// allocate a texture name
glGenTextures( 1, &texture );
```

Now that we have our texture name, we can switch between different textures we want using the function glBindTxeture. This essentially chooses what texture we are working with.

```// select our current texture
glBindTexture( GL_TEXTURE_2D, texture );
```

Texture Parameters:

Now we can begin to work on our current texture. Before we start, we should set one little texture environment state which tells OpenGL how the texture will act when it is rendered into a scene.

```// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
```

Next, we have four texture parameters we need to setup. Here is where we can setup such wonderful effects like bilinear and trilinear texture filtering, and mipmapping. We also can setup whether the texture wraps over at the edges or is clamped at the ends. The most common feature used is 'repeating'.

```// when texture area is small, bilinear filter the closest mipmap
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST );
// when texture area is large, bilinear filter the original
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

// the texture wraps over at the edges (repeat)
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
```

6. Sample examples

A Checker board

 ```//checker.cpp #include #include #include #include #include /* Create checkerboard texture */ #define checkImageWidth 64 #define checkImageHeight 64 static GLubyte checkImage[checkImageHeight][checkImageWidth][4]; static GLuint texName; void makeCheckImage(void) { int i, j, c; for (i = 0; i < checkImageHeight; i++) { for (j = 0; j < checkImageWidth; j++) { c = ((((i&0x8)==0)^((j&0x8))==0))*255; checkImage[i][j][0] = (GLubyte) c; checkImage[i][j][1] = (GLubyte) c; checkImage[i][j][2] = (GLubyte) c; checkImage[i][j][3] = (GLubyte) 255; } } } void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); makeCheckImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glBindTexture(GL_TEXTURE_2D, texName); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glEnd(); glFlush(); glDisable(GL_TEXTURE_2D); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -3.6); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(250, 250); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } ```

Cube with texture images

 ```/* * cubemap.cpp ( Demo for CS 520 ): Draw a cube with texture images. The cube can be rotated * by pressing keys 'x', 'X', 'y', 'Y', 'z', 'Z'. * Images are downloaded from Internet. * @Author: T.L. Yu, 2008F * */ #include #include #include #include #include #include #include "imageio.h" int texImageWidth; int texImageHeight; int window; static GLuint texName[6]; //texture names int anglex= 0, angley = 0, anglez = 0; //rotation angles //images for texture maps for 6 faces of cube char maps[][20] = {"cubemap_fr.png", "cubemap_bk.png", "cubemap_rt.png", "cubemap_lf.png", "cubemap_up.png", "cubemap_dn.png" }; //load texture image GLubyte *makeTexImage( char *loadfile ) { int i, j, c, width, height; GLubyte *texImage; /* Only works for .png or .tif images. NULL is returned if errors occurred. loadImageRGA() is from imageio library downloaded from Internet. */ texImage = loadImageRGBA( (char *) loadfile, &width, &height); texImageWidth = width; texImageHeight = height; return texImage; } void init(void) { glClearColor (0.2, 0.2, 0.8, 0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //texName is global glGenTextures(6, texName); for ( int i = 0; i < 6; ++i ) { GLubyte *texImage = makeTexImage( maps[i] ); if ( !texImage ) { printf("\nError reading %s \n", maps[i] ); continue; } glBindTexture(GL_TEXTURE_2D, texName[i]); //now we work on texName glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texImageWidth, texImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage); delete texImage; //free memory holding texture image } } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); float x0 = -1.0, y0 = -1, x1 = 1, y1 = 1, z0 = 1; float face[6][4][3] = { {{x0, y0, z0}, {x1, y0, z0}, {x1, y1, z0}, {x0, y1, z0}}, //front {{x0, y1, -z0}, {x1, y1, -z0}, {x1, y0, -z0}, {x0, y0, -z0}}, //back {{x1, y0, z0}, {x1, y0, -z0}, {x1, y1, -z0}, {x1, y1, z0}}, //right {{x0, y0, z0}, {x0, y1, z0}, {x0, y1, -z0}, {x0, y0, -z0}}, //left {{x0, y1, z0}, {x1, y1, z0}, {x1, y1, -z0}, {x0, y1, -z0}}, //top {{x0, y0, z0}, {x0, y0, -z0}, {x1, y0, -z0}, {x1, y0, z0}} //bottom }; glEnable( GL_CULL_FACE ); glCullFace ( GL_BACK ); glPushMatrix(); glRotatef( anglex, 1.0, 0.0, 0.0); //rotate the cube along x-axis glRotatef( angley, 0.0, 1.0, 0.0); //rotate along y-axis glRotatef( anglez, 0.0, 0.0, 1.0); //rotate along z-axis for ( int i = 0; i < 6; ++i ) { //draw cube with texture images glBindTexture(GL_TEXTURE_2D, texName[i]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3fv ( face[i][0] ); glTexCoord2f(1.0, 0.0); glVertex3fv ( face[i][1] ); glTexCoord2f(1.0, 1.0); glVertex3fv ( face[i][2] ); glTexCoord2f(0.0, 1.0); glVertex3fv ( face[i][3] ); glEnd(); } glPopMatrix(); glFlush(); glDisable(GL_TEXTURE_2D); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'x': anglex = ( anglex + 3 ) % 360; break; case 'X': anglex = ( anglex - 3 ) % 360; break; case 'y': angley = ( angley + 3 ) % 360; break; case 'Y': angley = ( angley - 3 ) % 360; break; case 'z': anglez = ( anglez + 3 ) % 360; break; case 'Z': anglez = ( anglez - 3 ) % 360; break; case 27: /* escape */ glutDestroyWindow(window); exit(0); } glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt ( 0, 0, 5, 0, 0, 0, 0, 1, 0 ); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); window = glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } ```

 void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); Defines a two-dimensional texture. The target parameter is set to either the constant GL_TEXTURE_2D or GL_PROXY_TEXTURE_2D. You use the level parameter if you're supplying multiple resolutions of the texture map; with only one resolution, level should be 0.

 void glCopyTexImage2D(GLenum target, GLint level, GLint internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); Creates a two-dimensional texture, using framebuffer data to define the texels. The pixels are read from the current GL_READ_BUFFER and are processed exactly as if glCopyPixels() had been called but stopped before final conversion. The settings of glPixelTransfer*() are applied. The target parameter must be set to the constant GL_TEXTURE_2D. The level, internalFormat, and border parameters have the same effects that they have for glTexImage2D(). The texture array is taken from a screen-aligned pixel rectangle with the lower-left corner at coordinates specified by the (x, y) parameters. The width and height parameters specify the size of this pixel rectangle. Both width and height must have the form 2m+2b, where m is a nonnegative integer (which can have a different value for width than for height) and b is the value of border.

Sphere with texture images

• May use GL_TRIANGLE_STRIP ( faster ) or GL_QUAD_STRIP
 ```/* Create a sphere centered at c, with radius r, and precision n. Draw a point for zero radius spheres */ typedef struct { double x; double y; double z; } XYZ; void CreateSphere(XYZ c,double r,int n) { int i,j; double phi1,phi2,theta, s, t; XYZ e,p; if (r < 0) r = -r; if (n < 0) n = -n; if (n < 4 || r <= 0) { glBegin(GL_POINTS); glVertex3f(c.x,c.y,c.z); glEnd(); return; } for (j=0;j < n; j++) { phi1 = j * TWOPI / n; phi2 = (j + 1) * TWOPI / n; //next phi glBegin(GL_QUAD_STRIP); for (i=0;i < = n;i++) { theta = i * PI / n; e.x = sin ( theta ) * cos ( phi2 ); e.y = sin ( theta ) * sin ( phi2 ); e.z = cos ( theta ); p.x = c.x + r * e.x; p.y = c.y + r * e.y; p.z = c.z + r * e.z; glNormal3f(e.x,e.y,e.z); s = phi2 / TWOPI; // column t = 1 - theta/PI; // row glTexCoord2f(s, t); glVertex3f(p.x,p.y,p.z); e.x = sin ( theta ) * cos ( phi1 ); e.y = sin ( theta ) * sin ( phi1 ); e.z = cos ( theta ); p.x = c.x + r * e.x; p.y = c.y + r * e.y; p.z = c.z + r * e.z; glNormal3f(e.x,e.y,e.z); s = phi1/TWOPI; // column t = 1 - theta/PI; // row glTexCoord2f(s, t); glVertex3f(p.x,p.y,p.z); } glEnd(); } }```

7. Environment Mapping

• A type of reflection mapping, particularly useful in animation.

• Law of Reflection:
1. Angle of reflection is equal and opposite to the incident angle, with respect to the surface normal.
2. Consequence of this law: If a point P is a distance d in front of the surface (measured in the direction of the surface normal), then its reflected point P' appears to be the same distance d behind the surface.

• Faking a reflection of a flat surface is quite simple: make a duplicate of the scene, but subjected to a reflection transformation so that all the duplicated objects are behind the reflecting surface.

• Faking the reflection from a complex surface (such as a sphere) is more difficult. One way to do it is to use environment mapping:
1. Use a wide angle projection from the center of the complex (e.g. spherical) object towards the camera position, and save the image.
2. Use this image as a spherical texture map for the object. Use OpenGL's automatic texture coordinate generation utilities.

• Introducted by Blinn and Newell in 1976.

• A two step process.

• Consider specular reflection from a surface

• We first render the scene without the mirror polygon.

• Place the camera at the center of the mirror pointed in the direction of the mirror normal, and thus obtain the scene of the environment as seen by the mirror.

• Put the mirror polygon back back and paste the previously obtained image of the scene as texture onto the mirror.

• To obtain more accurate images, we can project the environment onto a sphere

• The equations for generating texture coordinates can be obtained by reflection mapping:
• Assume texture map in the plane z = -d with d > 0 ( from the viewer's point of view )

• Project backwards orthogonally towards a unit sphere centered at the origin.

• Normal of a unit sphere with center at origin, at point ( x, y, z, 1 ) is (x, y, z, 0 ). The unit normal at (x, y, z) on the sphere is
n = (x, y, z) = (s, t, √(1.0 - s2 - t2)

• Suppose our camera is position at infinity looking towards the -z direction.

• The direction of reflection can be computed by
r = 2(n . v)n - v       --- (1)
where
v = (0, 0, 1) is the direction of the vertex V on the object to the eye.
n = (s, t, √(1.0 - s2 - t2) is the unit normal
So,
n . v = √(1.0 - s2 - t2 )

• From (1) we can solve for s and t:
rx = 2 √(1.0 - s2 - t2 ) s     -- (2a)
ry = 2 √(1.0 - s2 - t2 ) t     -- (2b)
rz = 2 (1.0 - s2 - t2 ) - 1     -- (2c)

From (2c), we have

√(1.0 - s2 - t2 ) = √( (rz + 1 ) / 2 )     -- (2d)

Substituting (2d) into (2a) and (2b), we obtain,

Note that

• OpenGL supports a variation of this method called sphere mapping:

 glTexGen(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGen(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T);

Example

 ```/* * CS 520: environment-map.cpp * Demonstrates the creation of environment map using the command * glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 500, 500, 0); * The scene can be rotated by pressing keys 'x', 'X', 'y', 'Y', 'z', 'Z'. * @Author: T.L. Yu, 2008F * */ #include #include #include #include #include int window; int anglex= 0, angley = 0, anglez = 0; //rotation angles void init(void) { glClearColor (0.9, 0.9, 0.8, 0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); float light_ambient[4] = { 0.1, 0.1, 0.1, 1.0 }; // r, g, b, a float light_diffuse[4] = { 0.9, 0.8, 0.9, 1.0 }; // r, g, b, a float light_position[4] = { 1.0, 1.0, 1.0 , 0.0 }; // x, y, z, w glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHT0); // enable automatic texture coordinate generation glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); } //rotate the objects void rotate() { glRotatef( anglex, 1.0, 0.0, 0.0); //rotate along x-axis glRotatef( angley, 0.0, 1.0, 0.0); //rotate along y-axis glRotatef( anglez, 0.0, 0.0, 1.0); //rotate along z-axis } //arbitrarily draw something void drawScene() { glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glColor3f ( 1, 0, 0 ); glPointSize ( 8 ); //draw a red point glBegin ( GL_POINT ); glVertex3f ( 1, 2, 2 ); glEnd(); glColor3f ( 0, 1, 0 ); //draw a green triangle glBegin ( GL_TRIANGLES); glVertex3f ( 2, 2, -2 ); glVertex3f ( 2, 3, -3 ); glVertex3f ( 2, 2, -3 ); glEnd(); glColor3f ( 0.1, 0.1, 0.8 ); //draw a blue teapot at left side glPushMatrix(); glTranslatef( -1.0, -1.0, 2.5 ); glRotatef( 45, 1, 1, 1 ); glutSolidTeapot( 1 ); glPopMatrix(); glEnable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //blend texture with lighting glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glLoadIdentity(); gluLookAt ( 0, 0, 0, 5, 0, 0, 0, 0, 1 ); //put camera at center of origin glScalef ( 1, -1, 1 ); //flip left-right rotate(); drawScene(); //Use current framebuffer image as texture glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 500, 500, 0); //clear frame buffer to draw sphere with scene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //put camera back at the observational point gluLookAt ( 5, 0, 0, 0, 0, 0, 0, 0, 1 ); rotate(); drawScene(); glutSolidSphere( 1.0, 20, 20 ); // draw a sphere with this sphere map glFlush(); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'x': anglex = ( anglex + 3 ) % 360; break; case 'X': anglex = ( anglex - 3 ) % 360; break; case 'y': angley = ( angley + 3 ) % 360; break; case 'Y': angley = ( angley - 3 ) % 360; break; case 'z': anglez = ( anglez + 3 ) % 360; break; case 'Z': anglez = ( anglez - 3 ) % 360; break; case 'r': anglex = angley = anglez = 0; break; case 27: /* escape */ glutDestroyWindow(window); exit(0); } glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-4.0, 4.0, -4.0 * (GLfloat) h / (GLfloat) w, 4.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt ( 5, 0, 0, 0, 0, 0, 0, 0, 1 ); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); window = glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } ```

8. Bump Mapping

• Textures not effective for modeling rough surfaces, such as orange skins and roads.

• Instead, we perturb the surface normals slightly, leading to slight alternation of lighting and, giving the illusion of a rough surface.

• First reported by Jim Blinn in 1988.

• The normal at a point on a surface characterizes the shape of the surface at that point.

• By perturbing the normal, we create a surface of small variations ( bump map ).

• The normal at the point p(u,v) is given by
where

• Suppose we move the surface by a small amount d(u,v) in the normal direction:
p'(u,v) = p(u,v) + d(u,v) n

• Normal at the perturbed point p':
n' = pu' x pv'

• We can compute the two partial derivatives by differentiating the equation for p':

If |d(u,v)| << 1, we can drop the last terms in the equations and we have (note that n x n = 0):

• The displacement δ = n' - n must lie in the tangenet plane at p.

• Therefore, given the bump map d(u,v), we find n' at each u,v location on the surface, and use n' for lighting calculations.

• We need two arrays to hold the values of ∂d/∂ u and ∂d/∂ v. This can be done using an image processing technique. Suppose we have a sampled version of d(u, v) as an array of pixels D = [dij]. Then,

9. More Texture Examples of using OpenGL

Spherical Map:

 ```// enable automatic texture coordinate generation glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); // suppose that the texture has been loaded to texImage glBindTexture(GL_TEXTURE_2D, texImage); glPushMatrix(); glutSolidTeapot(1); // draw a teapot with this sphere map glBindTexture(GL_TEXTURE_2D, texImage); glTranslatef(1.5,1.5,0.0); glutSolidSphere(1.0,20,20); // draw a sphere with this sphere map glPopMatrix(); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); ```

Cube Maps:

• In the cube map method, instead of having a sphere surrounding a point, we have a cube surrounding a point.

• A cube consists of six faces. Therefore, we take a picture of the environment from the point towards each of the six faces.

• We then use this as the environment map.

• The s and t texture coordinates to use for any vertex, like in the sphere map, are dependant on the normal of the vertex.

Automatic Texture Coordinates Generation:

• Automatic texture coordinates generation can be used for purposes other than spherical environment mapping.

• They can simply be used to automatically generate the texture coordinates of an object.

• Use GL_OBJECT_LINEAR instead of GL_SPHERE_MAP if you want to use the vertex coordinates rather than vertex normals to generate texture coordinates.

 ```/* * env-torus.cpp ( Demo for CS 520 ): Draw a torus with texture images using * automatic texture coordinates generation. Modulate mode is used so that * texture color is combined with lighting effects. * The torus can be rotated by pressing keys 'x', 'X', 'y', 'Y', 'z', 'Z'. * Texture image is downloaded from Internet. * @Author: T.L. Yu, 2008F * */ #include #include #include #include #include #include #include #include "imageio.h" int texImageWidth; int texImageHeight; int window; static GLuint texName; //texture name int anglex= 0, angley = 0, anglez = 0; //rotation angles char maps[] = {"glass.png"}; //texture file //load texture image GLubyte *makeTexImage( char *loadfile ) { int i, j, c, width, height; GLubyte *texImage; /* Only works for .png or .tif images. NULL is returned if errors occurred. loadImageRGA() is from imageio library downloaded from Internet. */ texImage = loadImageRGBA( (char *) loadfile, &width, &height); texImageWidth = width; texImageHeight = height; return texImage; } void init(void) { float light_ambient[4] = { 0.1, 0.1, 0.1, 1.0 }; // r, g, b, a float light_diffuse[4] = { 1.0, 1.0, 0.9, 1.0 }; // r, g, b, a //directional used float light_position[4] = { 1.0, 1.0, 1.0 , 0.0 }; // x, y, z, w glClearColor (0, 0, 0, 0.0); //black glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHT0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //texName is global glGenTextures(1, &texName); // enable automatic texture coordinate generation GLubyte *texImage = makeTexImage( maps ); if ( !texImage ) { printf("\nError reading %s \n", maps ); return; } glBindTexture(GL_TEXTURE_2D, texName); //now we work on texName glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //mix with light glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texImageWidth, texImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage); delete texImage; //free memory holding texture image //automatic texture coordinates generation glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_2D); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef( anglex, 1.0, 0.0, 0.0); //rotate along x-axis glRotatef( angley, 0.0, 1.0, 0.0); //rotate along y-axis glRotatef( anglez, 0.0, 0.0, 1.0); //rotate along z-axis glutSolidTorus(1.0, 2, 30,30); glPopMatrix(); glFlush(); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'x': anglex = ( anglex + 3 ) % 360; break; case 'X': anglex = ( anglex - 3 ) % 360; break; case 'y': angley = ( angley + 3 ) % 360; break; case 'Y': angley = ( angley - 3 ) % 360; break; case 'z': anglez = ( anglez + 3 ) % 360; break; case 'Z': anglez = ( anglez - 3 ) % 360; break; case 'r': anglex = angley = anglez = 0; break; case 27: /* escape */ glutDestroyWindow(window); exit(0); } glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-4.0, 4.0, -4.0 * (GLfloat) h / (GLfloat) w, 4.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt ( 5, 0, 0, 0, 0, 0, 0, 0, 1 ); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); window = glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } ```