1
votes

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;
}
1
If you want smooth shading you will have to do it in the fragment shader to benefit from interpolated normals. I'll write a more complete answer if not done already when I have access to a computerZouch
@Zouch I checked this example and there gouraud shading implemented in vertex shader and just color was interpolated.Stas Jus
Yes, but it is not "smooth" shading. You can get "smoother" result by computing "smooth" normals as LJᛃ stated it in his answer. You can also subdivide the mesh (to get more triangles). But in the end, you will never get smooth shading. For that you need to interpolate your normals (which is an automatic process done by the GPU when rasterizing) and use those interpolated normals for your shading in the fragment shader.Zouch
@Zouch in case if I want to subdivide mesh I need to change my vertices data, right? So, and as I understood from LJᛃ answer and articles from net that whole idea in shading is how to compute normals. Of course there is a thing with math in a fragment shader, but still?Stas Jus
What @Zouch is referring to is per-pixel lighting which is a separate concept that requires averaged normals as well, Also I'd like to refute that "gouraud shading is not "smooth" shading" as per-vertex gouraud shading is commonly referred to as smooth shading.LJᛃ

1 Answers

2
votes

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