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

GLSL II

2. Vertex Processor:
• Takes in vertices
• Position attribute
• Possibly color
• OpenGL state
• Produces fragments
• Position in clip coordinates
• Vertex color

3. Vertex attributes are named in the shaders

5. Application can get index from table and tie it to an application variable

6. Similar process for uniform variables

7. Vertex Attributes Example:
 ``` GLint colorAttrib; colorAttrib = glGetAttribLocation(myProgObj, "myColor"); /* myColor is name in shader */ GLfloat color[4]; glVertexAttrib4fv(colorAttrib, color); /* color is variable in application */ ```

• Moving vertices
• Morphing
• Wave motion
• Fractals
• Lighting
• More realistic models
9. (Uniform variable values cannot be changed between glBegin/glEnd.

10. Uniform Variable Example:
 ``` GLint xParam; xParam = glGetUniformLocation(myProgObj, "x"); /* x defined in shader */ /* my_x set in application */ GLfloat my_x; my_x = 5.0 /* or some other value */ glUniform1f(myProgObj, xParam, my_x); ```

 ``` uniform float time; uniform float xs, zs; void main() { float s; s = 1.0 + 0.1*sin(xs*time)*sin(zs*time); gl_Vertex.y = s*gl_Vertex.y; gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; } ```

12. Particle Systems

Ignoring friction:

x(t) = x0 + vxt,

y(t) = y0 + vyt + g * t2/2,

z(t) = z0 + vzt.

 ``` attribute vec3 vel; uniform float time; void main() { float g = -10; float t; t = time; vec4 object_pos = gl_Vertex; object_pos.x = object_pos.x + vel.x*t; object_pos.y = object_pos.y + vel.y*t + g/(2.0)*t*t; object_pos.z = object_pos.z + vel.z*t; gl_Position = gl_ModelViewProjectionMatrix * object_pos; } ```

 ```/* tempcolor.cpp Sample program showing how to pass parameters to GL shader programs. Shader sources are in files "tempcolor.vert" and "tempcolor.frag". @Author: T.L. Yu, 2008 */ #include #include #include #include #include #include #define GLEW_STATIC 1 #include #include #include using namespace std; /* Global handles for the currently active program object, with its two shader objects */ GLuint programObject = 0; GLuint vertexShaderObject = 0; GLuint fragmentShaderObject = 0; static GLint win = 0; int readShaderSource(char *fileName, GLchar **shader ) { // Allocate memory to hold the source of our shaders. FILE *fp; int count, pos, shaderSize; fp = fopen( fileName, "r"); if ( !fp ) return 0; pos = (int) ftell ( fp ); fseek ( fp, 0, SEEK_END ); //move to end shaderSize = ( int ) ftell ( fp ) - pos; //calculates file size fseek ( fp, 0, SEEK_SET ); //rewind to beginning if ( shaderSize <= 0 ){ printf("Shader %s empty\n", fileName); return 0; } *shader = (GLchar *) malloc( shaderSize); if ( *shader == NULL ) printf("memory allocation error\n"); // Read the source code count = (int) fread(*shader, 1, shaderSize, fp); (*shader)[count] = '\0'; if (ferror(fp)) count = 0; fclose(fp); return 1; } // public int installShaders(const GLchar *vertex, const GLchar *fragment) { GLint vertCompiled, fragCompiled; // status values GLint linked; // Create a vertex shader object and a fragment shader object vertexShaderObject = glCreateShader(GL_VERTEX_SHADER); fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER); // Load source code strings into shaders, compile and link glShaderSource(vertexShaderObject, 1, &vertex, NULL); glShaderSource(fragmentShaderObject, 1, &fragment, NULL); glCompileShader(vertexShaderObject); glGetShaderiv(vertexShaderObject, GL_COMPILE_STATUS, &vertCompiled); glCompileShader( fragmentShaderObject ); glGetShaderiv( fragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled); if (!vertCompiled || !fragCompiled) return 0; // Create a program object and attach the two compiled shaders programObject = glCreateProgram(); glAttachShader( programObject, vertexShaderObject); glAttachShader( programObject, fragmentShaderObject); // Link the program object glLinkProgram(programObject); glGetProgramiv(programObject, GL_LINK_STATUS, &linked); if (!linked) return 0; // Install program object as part of current state glUseProgram(programObject); //Set up initial uniform values GLchar names[][20] = { "CoolestColor", "HottestColor", "CoolestTemp", "TempRange" }; GLint loc[10]; for ( int i = 0; i < 4; ++i ) { loc[i] = glGetUniformLocation(programObject, names[i]); if (loc[i] == -1) printf("No such uniform named %s\n", names[i]); } glUniform3f(loc[0], 0.0, 0.0, 1); glUniform3f(loc[1], 1.0, 0.0, 0.0); glUniform1f(loc[2], 0.0); glUniform1f(loc[3], 1.0); return 1; } int init(void) { const char *version; GLchar *VertexShaderSource, *FragmentShaderSource; int loadstatus = 0; version = (const char *) glGetString(GL_VERSION); if (version[0] != '2' || version[1] != '.') { printf("This program requires OpenGL 2.x, found %s\n", version); exit(1); } readShaderSource("tempcolor.vert", &VertexShaderSource ); readShaderSource("tempcolor.frag", &FragmentShaderSource ); loadstatus = installShaders(VertexShaderSource, FragmentShaderSource); return loadstatus; } static void Reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -15.0f); } void CleanUp(void) { glDeleteShader(vertexShaderObject); glDeleteShader(fragmentShaderObject); glDeleteProgram(programObject); glutDestroyWindow(win); } static void Idle(void) { glutPostRedisplay(); } static void Key(unsigned char key, int x, int y) { switch(key) { case 27: CleanUp(); exit(0); break; } glutPostRedisplay(); } void display(void) { GLfloat vec[4]; int loc; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor( 1.0, 1.0, 1.0, 0.0 ); //get white background color glColor3f ( 1, 0, 0 ); //red, this will have no effect if shader is loaded loc = glGetAttribLocation(programObject, "VertexTemp" ); glBegin ( GL_QUADS ); if (loc == -1) printf("No such attribute named %s\n", "VertexTemp" ); //lowever left conrner is coldest ( blue ), upper left hottest ( red ) glVertexAttrib1f(loc, 0.1); //set temperature at the vertex to 0.1 glVertex3f ( -2.2, -2.2, 0 ); glVertexAttrib1f(loc, 0.2); //set temperature at the vertex to 0.2 glVertex3f ( 2.2, -2.2, 0 ); glVertexAttrib1f(loc, 0.4); glVertex3f ( 2.2, 2.2, 0 ); glVertexAttrib1f(loc, 0.8); glVertex3f ( -2.2, 2.2, 0 ); glEnd(); glutSwapBuffers(); glFlush(); } int main(int argc, char *argv[]) { int success = 0; glutInit(&argc, argv); glutInitWindowPosition( 0, 0); glutInitWindowSize(200, 200); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); win = glutCreateWindow(argv[0]); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutDisplayFunc(display); glutIdleFunc(Idle); // Initialize the "OpenGL Extension Wrangler" library glewInit(); success = init(); if ( success ) glutMainLoop(); return 0; } ``` ```//tempcolor.vert //uniform qualified variables are changed at most once per primitives uniform float CoolestTemp; uniform float TempRange; //attribute qualified variables are typically changed per vertex attribute float VertexTemp; //varying qualified variables communicate from the vertex shader to //the fragment shader varying float Temperature; void main(void) { //compute a temperature to be interpolated per fragment // in the range [0.0, 1.0] Temperature = ( VertexTemp - CoolestTemp ) / TempRange; //Temperature = ( 1.0 - CoolestTemp ) / TempRange; gl_Position = ftransform(); /* Same as: gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; */ } ``` ```/* tempcolor.frag: uniform qualified variables are changed at most once per primitive by the application, and vec3 declares a vector of three floating-point numbers. */ uniform vec3 CoolestColor; uniform vec3 HottestColor; varying float Temperature; void main(void) { //get a color between coolest and hottest colors, using the // mix() built-in function vec3 color = mix ( CoolestColor, HottestColor, Temperature ); //make a color with alpha of 1.0 gl_FragColor = vec4(color, 1.0); } ```

I = Ia + Id + Is

Phong Model ( Sum of lights from ambient reflection, diffuse reflection, and specular reflection )

Without distance term:

15. I = cdIdinL.N + csIsin(H.n)α + caIain

16. Assume single light source ( GL_LIGHT0 ) and material properties have been defined in the OpenGL program.

17. Compute all necessary vectors in eye coordinates:
• Transform normal to eye coordinate and normalize:
vec3 N = normalize(gl_NormalMatrix * gl_Normal);

• Represent the vertex in eye coordinate:
vec4 eyeVertex = gl_ModelViewMatrix * gl_Vertex;

18. Light source i is available as built-in uniform variable gl_LightSource[i]. Compute light position from light source vector:
vec4 eyeLightPos = gl_LightSource[0].position;
vec3 L = normalize( eyeLightPos.xyz - eyeVertex);

In eye coordinates, the normalized vector from the vertex to the eye ( origin ) is:

vec3 E = -normalize ( eyeVertex.xyz );

19. The normalized reflection vector is:
vec3 R = reflect( L, N );

20. The normalized halfway vector is:
vec3 H = normalize ( L + E );
21.  ``` void main(void) /* modified Phong vertex shader (without distance term) */ { float f; /* compute normalized normal, light vector, view vector, half-angle vector in eye cordinates */ vec3 norm = normalize(gl_NormalMatrix*gl_Normal); vec3 lightv = normalize(gl_LightSource[0].position -gl_ModelViewMatrix*gl_Vertex); vec3 viewv = -normalize(gl_ModelViewMatrix*gl_Vertex); vec3 halfv = normalize(lightv + norm); if(dot(lightv, norm) > 0.0) f = 1.0; else f = 0.0; /* compute diffuse, ambient, and specular contributions */ vec4 diffuse = max(0, dot(lightv, norm))*gl_FrontMaterial.diffuse *gl_LightSource[0].diffuse; vec4 ambient = gl_FrontMaterial.ambient*gl_LightSource[0].ambient; vec4 specular = f*gl_FrontMaterial.specular*gl_LightSource[0].specular *pow(max(0, dot( norm, halfv)), gl_FrontMaterial.shininess); vec3 color = vec3(ambient + diffuse + specular); gl_FrontColor = vec4(color, 1); gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; } ```

23. Rasterization
• Geometric entities are rasterized into fragments
• Each fragment corresponds to a point on an integer grid: a displayed pixel Hence each fragment is a potential pixel
• Each fragment has
• A color
• Possibly a depth value
• Texture coordinates

24. Fragment Operations
• Texture generation
• Fog
• Antialiasing
• Scissoring
• Alpha test
• Blending
• Dithering
• Logical Operation

• Per fragment lighting calculations
 per vertex lighting(standard) per fragment lighting(programmed)

• Texture mapping
 Smooth Shading Environment Mapping Bump Mapping

26. Fragment Shader for Modified Phong Lighting

 ``` //phong.vert varying vec3 N; varying vec3 L; varying vec3 E; void main(void) { gl_Position =gl_ModelViewMatrix*gl_Vertex; vec4 eyePosition = gl_ModelViewProjectionMatrix*gl_Vertex; vec4 eyeLightPosition = gl_LightSource[0].position; N = normalize( gl_NormalMatrix*gl_Normal ); L = eyeLightPosition.xyz - eyePosition.xyz; E = -eyePosition.xyz; } ```
 ``` //phong.frag varying vec3 N; varying vec3 L; varying vec3 E; void main() { vec3 norm = normalize(N); vec3 lightv = normalize(L); vec3 viewv = normalize(E); vec3 halfv = normalize(lightv + viewv); float f; if(dot(lightv, norm)>= 0.0) f =1.0; else f = 0.0; float Kd = max(0.0, dot(lightv, norm)); float Ks = pow(max(0.0, dot(norm, halfv)), gl_FrontMaterial.shininess); vec4 diffuse = Kd * gl_FrontMaterial.diffuse*gl_LightSource[0].diffuse; vec4 ambient = gl_FrontMaterial.ambient*gl_LightSource[0].ambient; vec4 specular = f * Ks * gl_FrontMaterial.specular*gl_LightSource[0].specular; gl_FragColor = ambient + diffuse + specular; } ```

27. Samplers
-Defined for 1, 2, and 3 dimensional textures and for cube maps

 ``` uniform sampler2D myTexture; vec2 texcoord; vec4 texcolor = texture2D(mytexture, texcoord); ```

-In application:

 ``` texMapLocation = glGetUniformLocation(myProg, "myTexture"); glUniform1i(texMapLocation, 0); /* assigns to texture unit 0 */ ```

--------

 ```// Vertex shader for procedural bricks // // Authors: Dave Baldwin, Steve Koren, Randi Rost // based on a shader by Darwyn Peachey // uniform vec3 LightPosition; const float SpecularContribution = 0.3; const float DiffuseContribution = 1.0 - SpecularContribution; varying float LightIntensity; varying vec2 MCposition; void main(void) { vec3 ecPosition = vec3 (gl_ModelViewMatrix * gl_Vertex); vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); vec3 lightVec = normalize(LightPosition - ecPosition); vec3 reflectVec = reflect(-lightVec, tnorm); vec3 viewVec = normalize(-ecPosition); float diffuse = max(dot(lightVec, tnorm), 0.0); float spec = 0.0; if (diffuse > 0.0) { spec = max(dot(reflectVec, viewVec), 0.0); spec = pow(spec, 16.0); } LightIntensity = DiffuseContribution * diffuse + SpecularContribution * spec; MCposition = gl_Vertex.xy; gl_Position = ftransform(); }``` ```// // Fragment shader for procedural bricks // uniform vec3 BrickColor, MortarColor; uniform vec2 BrickSize; uniform vec2 BrickPct; varying vec2 MCposition; varying float LightIntensity; void main(void) { vec3 color; vec2 position, useBrick; position = MCposition / BrickSize; if (fract(position.y * 0.5) > 0.5) position.x += 0.5; position = fract(position); useBrick = step(position, BrickPct); color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); color *= LightIntensity; gl_FragColor = vec4 (color, 1.0); } ```

Overall Effects:

29. A single light source

30. Diffuse and specular reflection characteristics

31. A brick pattern based on the position in modeling coordinates of the object being renderedâ€”where the x coordinate is related to the brick horizontal position and the y coordinate is related to the brick vertical position

32. Alternate rows of bricks offset by one-half the width of a single brick

33. Easy-to-modify colors and ratios: brick color, mortar color, brick-tobrick horizontal distance, brick-to-brick vertical distance, brick width fraction
Brick size, Brick percentage

35. What data must be passed to the vertex shader for every vertex (i.e., attribute variables)?

36. What global state is required by the vertex shader (i.e., uniform variables)?

37. What values are computed by the vertex shader (i.e., varying variables)?

38. Solutions:

• Need lighting position
`uniform vec3 LightPosition;`
• Can access current vertex position and normal position by gl_Vertex, and gl_Normal
• We also need values for the lighting calculation to represent the contribution from specular reflection and the contribution from diffuse reflection.
```	const float SpecularContribution = 0.3;
const float DiffuseContribution = 1.0 - SpecularContribution;
```
• We need to define the values that are passed on to the fragment shader; we define a varying variable MCposition to hold the position of a brick and LightIntensity to hold the light intensity value.
```	varying float LightIntensity;
varying vec2 MCposition;
```
• We compute the vertex position in eye coordinates
```	vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex);
```
• Compute lighting:
```	vec3 tnorm      = normalize(gl_NormalMatrix * gl_Normal);
vec3 lightVec   = normalize(LightPosition - ecPosition);
vec3 reflectVec = reflect(-lightVec, tnorm);
vec3 viewVec    = normalize(-ecPosition);
```
``` 	float diffuse   = max(dot(lightVec, tnorm), 0.0);
float spec      = 0.0;

if (diffuse > 0.0)
{
spec = max(dot(reflectVec, viewVec), 0.0);
spec = pow(spec, 16.0);
}

LightIntensity  = DiffuseContribution * diffuse +
SpecularContribution * spec;
MCposition      = gl_Vertex.xy;
gl_Position     = ftransform();
```

40. Compute the color of the fragments.

41. Use the following uniform variables for a brick:
```	uniform vec3  BrickColor, MortarColor;
uniform vec2  BrickSize;
uniform vec2  BrickPct;
```

42. Placement of the brick pattern is computed by the vertex shader and passed to the fragment shader by the varying variable MCposition

 ``` varying vec2 MCposition; .... vec2 position, useBrick; position = MCposition / BrickSize; ```

MCposition is the position of a vertex. So

• brick row number: postion.y
• brick column number: postion.x

43. Use a conditional to determine whether the fragment is in a row of bricks that is offset (see Figure below):
```	if (fract(position.y * 0.5) > 0.5)
position.x += 0.5;
```

44. We compute the fragment's location within the current brick:
```	position = fract(position);
```

45. User step() function to produce horizontal component of the brick pattern:
```	useBrick = step(position, BrickPct);
```
• 1: use brick color
• 0: use mortar color

47. We have to access the texture coordinates per vertex to perform texturing operations in GLSL.
48. GLSL provides built in attribute variables, one for each texture unit:
 ``` attribute vec4 gl_MultiTexCoord0; attribute vec4 gl_MultiTexCoord1; attribute vec4 gl_MultiTexCoord2; attribute vec4 gl_MultiTexCoord3; attribute vec4 gl_MultiTexCoord4; attribute vec4 gl_MultiTexCoord5; attribute vec4 gl_MultiTexCoord6; attribute vec4 gl_MultiTexCoord7; ```
49. The texture matrice of each texture unit can be accessed through a uniform array:
 ``` uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords]; ```

50. The vertex shader has to compute the texture coordinates for the vertex and store the values in the pre-defined varying variable gl_TexCoord[i]. For example,
 ``` gl_TexCoord[0] = gl_MultiTexCoord0; ```

51. We need to declare a special type of variable in the fragment shader to access the texture values from the application. For example,
 ``` uniform sampler2D texHandle; ```

52. The function texture2D() gives us a texel (texture element). It takes a sampler2D and texture coordinates as inputs and returns the texel value:
 ``` vec4 texture2D(sampler2D texHandle, vec2 gl_TexCoord[0].st ); ```

 ```// simpletex.vert // Vertex shader for drawing an object with one texture // varying float LightIntensity; uniform vec3 LightPosition; const float specularContribution = 0.1; const float diffuseContribution = 1.0 - specularContribution; void main(void) { vec3 ecPosition = vec3 (gl_ModelViewMatrix * gl_Vertex); vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); vec3 lightVec = normalize(LightPosition - ecPosition); vec3 reflectVec = reflect(-lightVec, tnorm); vec3 viewVec = normalize(-ecPosition); float spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0); spec = pow(spec, 16.0); LightIntensity = diffuseContribution * max(dot(lightVec, tnorm), 0.0) + specularContribution * spec; gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); } ```

 ```// simpletex.frag // Fragment shader for drawing an object with one texture // varying float LightIntensity; uniform sampler2D texHandle; void main (void) { vec3 lightColor = vec3 (texture2D(texHandle, gl_TexCoord[0].st)); gl_FragColor = vec4 (lightColor * LightIntensity, 1.0); } ```

Application setup:

 ```const int iWidth = 64, iHeight = 64; static GLubyte checkImage[iHeight][iWidth][3]; void init2DTexture() { makeCheckImage(); 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_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, checkImage ); } ..... glUniform3f(glGetUniformLocation(programObject, "LightPosition"), 2.0, 2.0, 4.0); glUniform1i(glGetUniformLocation(programObject, "texHandle"), 0); ..... glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texName); glutSolidTeapot(0.6f); //has texture coordinates ```
54. Cube Maps

55. We can form cube map texture by defining six 2D texture maps that correspond to the sides of a box
56. Supported by OpenGL
57. Also supported in GLSL through cubemap sampler

 ``` vec4 texColor = textureCube(mycube, texcoord); ```

58. Texture coordinates must be 3D

59. Can be used in environment mapping

-Use reflection vector to locate texture in cube map

60.  ``` //cubemap.vert : vertex shader void main() { gl_TexCoord[0].stp = gl_Vertex.xyz; gl_Position = gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;; } ```
 ``` //cubemap.frag : fragment shader uniform samplerCube cubeMap; void main() { gl_FragColor = textureCube(cubeMap, gl_TexCoord[0].stp); } ```

62. Perturb normal for each fragment
63. Store perturbation as textures ( called normal-map or bump-map ):
• The normal vector contained in a texel of a normal-map represents the vector perpendicular to the surface of an object on the considered texel.
• Without deformation, the normal vector is ( 0, 0, 1 ) as its XYZ components.
• A different vector, for example, ( 0.1, 0.2, 0.975 ), indicates a modification of the surface.
• A normal vector here always has unit length, i.e. (X2 + Y2 + Z2) = 1
64. Form an orthonormal frame of reference using vectors normal, tangent and binormal ( tangent space ):
X-axis = ( 1, 0, 0 ) ( tangent vector )
Y-axis = ( 0, 1, 0 ) ( binormal vector )
Z-axis = ( 0, 0, 1 ) ( normal vector )

The multiplication by the gl_NormalMatrix transforms the incoming normal to eye-space. The normalization
guarantees a unit length vector as required to compute the cosine with a dot product.

 ```//bump.vert varying vec3 lightVec; varying vec3 eyeVec; uniform vec3 LightPosition; void main(void) { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; //create vector from eye to vertex, vec3 constructor used eyeVec = vec3(gl_ModelViewMatrix * gl_Vertex); vec3 vTangent; vTangent.x = -gl_Normal.y; //vTangent perp to gl_Normal; may be from application vTangent.y = gl_Normal.x; vTangent.z = 0; vec3 n = normalize(gl_NormalMatrix * gl_Normal); vec3 t = normalize(gl_NormalMatrix * vTangent); vec3 b = cross(n, t); //Transform objects to local coordinate system XYZ //by rotation matrix M = (t, b, n) vec3 v; v.x = dot(LightPosition, t); v.y = dot(LightPosition, b); v.z = dot(LightPosition, n); lightVec = normalize ( v ); // v.x = dot(eyeVec, t); v.y = dot(eyeVec, b); v.z = dot(eyeVec, n); eyeVec = normalize ( v ); } ```

 ```//bump.frag varying vec3 lightVec; varying vec3 eyeVec; uniform vec3 SurfaceColor; uniform float BumpDensity; uniform float BumpSize; uniform float SpecularFactor; void main (void) { vec3 litColor; vec2 c = BumpDensity * gl_TexCoord[0].st; vec2 p = fract( c ) - vec2( 0.5 ); //normal map float d, f; d = p.x * p.x + p.y * p.y; f = 1.0 / sqrt ( d + 1.0 ); if ( d >= BumpSize ){ p = vec2 ( 0.0 ); f = 1.0; } vec3 normalDelta = vec3 ( p.x, p.y, 1.0 ) * f; litColor = SurfaceColor * max(dot(normalDelta, lightVec), 0.0 ); vec3 reflectVec = reflect ( lightVec, normalDelta ); float specular = max ( dot(eyeVec, reflectVec), 0.0 ); specular = pow ( specular, 6.0 ) * SpecularFactor; litColor = min ( litColor + specular, vec3(1.0) ); gl_FragColor = vec4 ( litColor, 1.0 ); } ```

68. Environment map usually computed in world coordinates which can differ from object coordinates because of modeling matrix

69. May have to keep track of modeling matrix and pass it to shader as a uniform variable

70. Can also use reflection map or refraction map (for example to simulate water)

71. Example: Consider spherical mapping:

• v is the unit vector going from the current vertex to the camera. So it is the position of the vertex in eye space and is also the view vector.
• n is the vertex normal in eye space.
• r is the reflected vision vector against the normal n:
r = reflect(v, n)
( i.e. r = 2 * ( n . v ) * n - v, see Texture Mapping )

• Texture coordinates are calculated:

• Spherical Environment Map Vertex Shader

 ```void main() { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; vec3 v = normalize( vec3(gl_ModelViewMatrix * gl_Vertex) ); vec3 n = normalize( gl_NormalMatrix * gl_Normal ); vec3 r = reflect( v, n ); float m = sqrt( 2* ( r.z+ 1) ) ; gl_TexCoord[1].s = r.x/m + 0.5; gl_TexCoord[1].t = r.y/m + 0.5; } ```

• Spherical Environment Map Fragment Shader

 ```uniform sampler2D colorMap; uniform sampler2D envMap; void main (void) { vec4 color = texture2D( colorMap, gl_TexCoord[0].st); vec4 env = texture2D( envMap, gl_TexCoord[1].st); gl_FragColor = color + env*0.4; } ```

At the OpenGL level, this shader is equivalent to the following instructions that enable the Spherical Environment Mapping for the active texture unit:
```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);
```
72. GLSL Full Documentation can be found at the following link:

http://oss.sgi.com/projects/ogl-sample/registry/ARB/GLSLangSpec.Full.1.10.59.pdf