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

    1. Vertex Shaders

    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

    4. Linker forms a table

    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 */
            

      (Attribute variables are read-only. Only for vertex shader.)

    8. Vertex shader applications:
      • Moving vertices
      • Morphing
      • Wave motion
      • Fractals
      • Lighting
      • More realistic models
      • Cartoon shaders
    9. (Uniform variable values cannot be changed between glBegin/glEnd.
      Can be read but not written in both shaders. ) )

    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);
         

    11. Wave Motion Vertex Shader
      
      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;
      }
         

    13. Temperature Shaders

      /*
        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 <stdlib.h>
      #include <stdio.h>
      #include <string.h>
      #include <fcntl.h>
      #include <sys/types.h>
      #include <unistd.h>
      
      #define GLEW_STATIC 1
      #include <GL/glew.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      
      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);	
      }
      

    14. Modified Phong Vertex Shader

      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;
      }
            

    22. Fragment Shaders

    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
      • Masking

    25. Fragment Shader Applications
      • 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
      -Provides access to a texture object
      -Defined for 1, 2, and 3 dimensional textures and for cube maps
      -In shader:

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

      -In application:

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

    28. Brick Shaders

      --------

      // 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
    34. Vertex Shader

    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();
        	
    39. Fragment Shader

    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

    46. Texture Shaders

    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 );
        	

    53. A simple texture shader.

      // 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);
         }
         

    61. Bump Maps with Shaders
    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 )

    65. Vertex shader

      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 );
      }
         

    66. Fragment shader

      //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 );
      }     
         

    67. Environment Maps with Shaders

    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