CS184 Section 4
Phong Illumination Model and GLSL

Brandon Wang
February 14, 2012
Material adapted from Fu-Chung Huang, Carlo Sequin, Niels Joubert.

Logistics

Today

Phong Illumination Model

What is it?

How we determine the color of what we see

i.e. Given our representations of geometry and lights, what color is at a specific pixel?

  • Ambient
  • Diffuse
  • Specular

Ambient term

\mathbf{I}_{A} = \mathbf{C}_{mat} \cdot \mathbf{L}_{amb}

\mathbf{C}_{mat}
Color of the material
\mathbf{L}_{amb}
Ambient light color

Does not depend on direction of light, or direction to viewer!

Diffuse term

\mathbf{I}_{D} = \mathbf{C}_{diff} \cdot \mathbf{L}_{col} \cdot max\left(\mathbf{N} \cdot \mathbf{L}_{dir}, 0\right)

\mathbf{C}_{diff}
Diffuse color of the material
\mathbf{L}_{col}
Light color
\mathbf{N}
Surface normal
\mathbf{L}_{dir}
Light direction

Specular Term

\mathbf{I}_{S} = \mathbf{C}_{spec} \cdot \mathbf{L}_{col} \cdot max\left(\mathbf{N} \cdot \mathbf{H}, 0\right)^{k_{sp}}

\mathbf{C}_{spec}
Specular color of the material
\mathbf{L}_{col}
Light color
\mathbf{N}
Surface normal
\mathbf{H}
Half angle
k_{sp}
Shininess

Phong Illumination Model

\mathbf{\rho} = \mathbf{C}_{a}\mathbf{L}_{a} + \sum_{Lights} \left( \mathbf{C}_{d}\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{L}_{dir}} \cdot \hat{\mathbf{n}}, 0) + \mathbf{C}_s\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{N}} \cdot \hat{\mathbf{r}}, 0)^{k_{sp}} \right) \\

Ambient Term

\mathbf{\rho} = \underline{\mathbf{C}_{a}\mathbf{L}_{a}} + \sum_{Lights} \left( \mathbf{C}_{d}\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{L}_{dir}} \cdot \hat{\mathbf{n}}, 0) + \mathbf{C}_s\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{N}} \cdot \hat{\mathbf{r}}, 0)^{k_{sp}} \right) \\

Diffuse Term

\mathbf{\rho} = \mathbf{C}_{a}\mathbf{L}_{a} + \sum_{Lights} \left( \underline{\mathbf{C}_{d}\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{L}_{dir}} \cdot \hat{\mathbf{n}}, 0)} + \mathbf{C}_s\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{N}} \cdot \hat{\mathbf{r}}, 0)^{k_{sp}} \right) \\

Specular Term

\mathbf{\rho} = \mathbf{C}_{a}\mathbf{L}_{a} + \sum_{Lights} \left( \mathbf{C}_{d}\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{L}_{dir}} \cdot \hat{\mathbf{n}}, 0) + \underline{\mathbf{C}_s\mathbf{L}_{col}\,\mathrm{max}(\hat{\mathbf{N}} \cdot \hat{\mathbf{r}}, 0)^{k_{sp}}} \right) \\

Questions

  1. How would the diffuse and specular term look like for a matte object? (Think chalk). What would some other objects be that have similar terms?
  2. How would the diffuse and specular term look like for a shiny plastic? (Think metal). What would some other objects be that have similar terms?
  3. What is flat shading?
  4. What is Gouraud shading?
  5. What is Phong shading?
  6. What is a point light?

GLSL

The vertex shader operates on vertices. You typically do transformations, texture coordinates, and per-vertex lighting on it.

The fragment shader operates on fragments, or visible pixels. The values you receive are interpolated from the vertex shader, and you typically add effects, compute per-fragment lighting, and output the actual pixel values.

The vertex shader typically comes before the fragment shader, and are two separate programs.

GLSL

Was my phong illumination calculation done at vertex or fragment here?

Data Types

Vector

Like a class or tuple.

Access it using:

vec4 color;
color.rgb = vec3(1.0 , 1.0 , 0.0 ); 
color.a = 0.5
color = vec4(1.0 , 1.0 , 0.0 , 0.5); 
color.xy = vec2(1.0 , 1.0); 
color.zw =vec2(0.0 , 0.5);

Variable Qualifiers

Qualifiers (in addition to variable type) specify the special attributes that vertex and fragment shaders have

Vertex Shader (HW1/2)

# version 120 

varying vec4 color ; 
varying vec3 mynormal ; 
varying vec4 myvertex ; 

void main() {
    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix 
                  * gl_Vertex ; 
    color = gl_Color ; 
    mynormal = gl_Normal ; 
    myvertex = gl_Vertex ; 
}
  

Fragment Shader (HW1/2) (Part 1 of 2)

# version 120 
varying vec4 color ;
varying vec3 mynormal ; 
varying vec4 myvertex ; 
uniform int islight ; // are we lighting. 
uniform vec4 light0posn ; 
uniform vec4 light0color ; 
uniform vec4 light1posn ; 
uniform vec4 light1color ; 
uniform vec4 ambient ; 
uniform vec4 diffuse ; 
uniform vec4 specular ; 
uniform float shininess ; 
vec4 ComputeLight (const in vec3 direction, const in vec4 lightcolor, 
  const in vec3 normal, const in vec3 halfvec, const in vec4 mydiffuse, 
  const in vec4 myspecular, const in float myshininess) {
        float nDotL = dot(normal, direction)  ;         
        vec4 lambert = mydiffuse * lightcolor * max (nDotL, 0.0) ;  
        float nDotH = dot(normal, halfvec) ; 
        vec4 phong = myspecular * lightcolor * pow (max(nDotH, 0.0), myshininess) ; 
        vec4 retval = lambert + phong ; 
        return retval ;            
}       
  

Fragment Shader (HW1/2) (Part 2 of 2)

void main (void) {
    if (islight == 0) gl_FragColor = color ; 
    else { 
        // They eye is always at (0,0,0) looking down -z axis 
        // Also compute current fragment position and direction to eye 
        const vec3 eyepos = vec3(0,0,0) ; 
        vec4 _mypos = gl_ModelViewMatrix * myvertex ; 
        vec3 mypos = _mypos.xyz / _mypos.w ; // Dehomogenize current location 
        vec3 eyedirn = normalize(eyepos - mypos) ; 
        // Compute normal, needed for shading. 
        // Simpler is vec3 normal = normalize(gl_NormalMatrix * mynormal) ; 
        vec3 _normal = (gl_ModelViewMatrixInverseTranspose*vec4(mynormal,0.0)).xyz ; 
        vec3 normal = normalize(_normal) ; 
        // Light 0, point
        vec3 position0 = light0posn.xyz / light0posn.w ; 
        vec3 direction0 = normalize (position0 - mypos) ; // no attenuation 
        vec3 half0 = normalize (direction0 + eyedirn) ;  
        vec4 col0 = ComputeLight(direction0, light0color, normal, half0, diffuse, 
                                specular, shininess) ;
        // Light 1, point 
        vec3 position1 = light1posn.xyz / light1posn.w ; 
        vec3 direction1 = normalize (position1 - mypos) ; // no attenuation 
        vec3 half1 = normalize (direction1 + eyedirn) ;  
        vec4 col1 = ComputeLight(direction1, light1color, normal, half1, diffuse, 
                                specular, shininess) ;
        gl_FragColor = ambient + col0 + col1 ; 
        }
}

Warning on a few things

GLSL is highly hardware dependent. Some versions of GLSL work on some GPUs, and not on others. Usually, you will face issues with control flow statements (if, else, for, while, etc). For HW2, you can try to use a for loop, but your mileage may vary.

It is very difficult to debug GLSL programs! You don't have any print statements, and the debuggers for GLSL are usually not that great. Something simple may be to set a pixel to be red if it is incorrect, but that's not that great of a debug tool.

Demonstration of shader effects

Bump Mapping

Demonstration of shader effects

Environment Mapping

Demonstration of shader effects

Shadow Mapping

Modern OpenGL Clarification

const GLfloat wd = 0.1 ; 
const GLfloat ht = 0.5 ; 
const GLfloat _cubecol[4][3] = { 
{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 1.0, 
0.0} } ; 
const GLfloat cubeverts[8][3] = {
{-wd, -wd, 0.0}, {-wd, wd, 0.0}, {wd, wd, 0.0}, {wd, -wd, 0.0},
{-wd, -wd, ht}, {wd, -wd, ht}, {wd, wd, ht}, {-wd, wd, ht}
} ; 
GLfloat cubecol[8][3] ;
const GLubyte cubeinds[6][4] = { 
{0, 1, 2, 3}, // BOTTOM 
{4, 5, 6, 7}, // TOP 
{0, 4, 7, 1}, // LEFT 
{0, 3, 5, 4}, // FRONT
{3, 2, 6, 5}, // RIGHT 
{1, 7, 6, 2}  // BACK
} ; 

Modern OpenGL Clarification

// Simple function to set the color separately.  Takes out colors
void initobjectnocol(GLuint object, GLfloat * vert, GLint sizevert, 
GLubyte * inds, GLint sizeind, GLenum type) {
int offset = object * numperobj ; 
glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
glBufferData(GL_ARRAY_BUFFER, sizevert, vert,GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
glEnableClientState(GL_VERTEX_ARRAY) ; 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,buffers[Elements+offset]) ; 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeind, inds,GL_STATIC_DRAW);
PrimType[object] = type ; 
NumElems[object] = sizeind ; 
}
//in init
initcolorscube() ; 
initobjectnocol(CUBE, (GLfloat *) cubeverts, sizeof(cubeverts), 
(GLubyte *) cubeinds, sizeof (cubeinds), GL_QUADS) ;