Shading

To render our geometry and take advantage of our normals, we require a shader that implements the lighting equation. This is a more sophisticated application of GLSL. Here is a summary of GLSL that covers everything we'll need to know.

The uniforms configure the transformation matrices and the lighting parameters. The attributes configure the vertices. The varyings define the values to be interpolated by the rasterizer. Pay close attention to their types.

〈Vertex Shader〉 ≡
  precision mediump float

  uniform mat4 projectionMatrix
  uniform mat4 viewMatrix
  uniform mat4 modelMatrix
  uniform vec4 lightPosition

  attribute vec4 vertexPosition
  attribute vec3 vertexNormal

  varying vec3 fragmentNormal
  varying vec3 fragmentLight
  varying vec3 fragmentView

The vertex shader uses the scene parameters defined by the attributes and uniforms to calculate $n$, $l$, and $v$, the inputs to the lighting model. Note, lighting calculations are done in eye space because this allows us to infer that the viewer sits at the origin.

  function main()
    modelViewMatrixviewMatrix · modelMatrix

    pmodelViewMatrix · vertexPosition
    qviewMatrix · lightPosition

    fragmentNormalnormalize(mat3(modelViewMatrix) · vertexNormal)
    fragmentLightnormalize(vec3(qp))
    fragmentViewnormalize(vec3(−p))

    gl_PositionprojectionMatrix · modelViewMatrix · vertexPosition

The lighting equation itself is implemented in the fragment shader. Here are the inputs.

〈Fragment Shader〉 ≡
  precision mediump float

  varying vec3 fragmentNormal
  varying vec3 fragmentLight
  varying vec3 fragmentView

  uniform vec3 modelColor
  uniform vec3 lightColor

And here is the calculation. We arbitrarily choose a constant specular exponent of 10, but this could easily be another uniform.

  function main()
    nnormalize(fragmentNormal)
    lnormalize(fragmentLight)
    vnormalize(fragmentView)
    hnormalize(l + v)

    dmax(l · n, 0)
    smax(h · n, 0)10

    fragmentColormodelColor · lightColor · d + lightColor · s

    gl_FragColorvec4(fragmentColor, 1.0)

As usual, don't forget to use gl.getUniformLocation, gl.uniformMatrix4f, gl.uniform3f, and gl.uniform4f in the application code to query the locations of each of these uniforms and give them a value.