javascriptopenglglslwebglshading

How to Gouraud shading with diffuse lighting in WebGl?


I stuck with implementing Gouraud smooth shading. I'm missing something and I need help.

First about diffuse lighting. To get diffuse light I'm using this formula:

Id * Kd * max( dot(N,L), 0.0)

I should get my diffuse color and I will add it to my ambient color.

Next shading. Gouraud shading is a shading per vertex. I found Gouraud shading algorithm in this lectures

As I understood this algorithm:

  1. Determine the normal at each polygon vertex
vec3 N = mat3(normalMatrix) * normals;
  1. Apply an illumination model to each vertex to calculate the vertex intensity
float labertian = max(dot(N, L), 0.0);
vec4 color = vec4(intensityAmbientColor * ambientColor
                 + intensityDiffuseColor * diffuseColor * labertian, 1.0);
  1. Linearly interpolate the vertex intensities over the surface polygon
v_color = color;

This is the output image

output image

What do I missing here? vertex shader:

attribute vec3 coordinates;
attribute vec3 normals;

/** MVP */
uniform mat4 modelMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 normalMatrix;
// uniform mat4 viewModelMatrixl

/** LIGHT */
uniform vec3 ambientColor;
uniform float intensityAmbientColor;

uniform vec3 diffuseColor;
uniform float intensityDiffuseColor;

uniform vec3 cameraCoordinates;
uniform vec3 lightCoordinates;

varying vec4 v_color;

void main() {

  gl_Position = projectionMatrix *
    viewMatrix *
    modelMatrix *
    vec4(coordinates, 1.0);

  vec3 surfaceWorldPosition = (
    viewMatrix
    * modelMatrix
    * vec4(coordinates, 1.0)
  ).xyz;

  vec3 L = lightCoordinates - surfaceWorldPosition;
  vec3 V = cameraCoordinates - surfaceWorldPosition;
  vec3 N = mat3(normalMatrix) * normals;

  float labertian = max(dot(N, L), 0.0);
  v_color = vec4(intensityAmbientColor * ambientColor
                 + intensityDiffuseColor * diffuseColor * labertian, 1.0);
}

fragment shader:

precision mediump float;

varying vec4 v_color;

void main() {
  gl_FragColor = v_color;
}

Solution

  • Gouraud shading is nothing more than averaging your vertex normals, usually this is part of mesh importers/exporters/converters, you can do it manually, however if your mesh isn't indexed you'd need to reindex it first to find the shared vertices, then average the normals across them. Right now you seem to render an unindexed mesh where each vertex is unique in relation to one face.

    An estimate to the surface normal of each vertex in a polygonal 3D model is either specified for each vertex or found by averaging the surface normals of the polygons that meet at each vertex.

    https://en.wikipedia.org/wiki/Gouraud_shading