juztcode
juztcode

Reputation: 1345

phong and goraud shading - need knowledge about how the fragments get shaded

The only practical difference about Phong shading and Goraud shading is that if the calculation of fragment color is done in the vertex shader then it's Goraud else it's phong. I've got a little code of vertex shader and fragment shader code below:

//vertexShader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 FragPos;
out vec3 Normal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;  

    gl_Position = projection * view * vec4(FragPos, 1.0);
}  


//FragmentShader.fs
#version 330 core
out vec4 FragColor;

in vec3 Normal;  
in vec3 FragPos;  

uniform vec3 lightPos; 
uniform vec3 viewPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0),32);
    vec3 specular = specularStrength * spec * lightColor;  

    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
} 

It turns out the Phong is a bit more smooth looking on low poly objects. So, the knowledge barrier is basically in how the fragments get shader. First let's look at what the wonderful resource learnopenGL already provides.

In summary, it tells us that the color value supplied at the vertices are interpolated within the boundary of the fragment made by the vertices. So, this is quite meaningful like something like an weighted average is taken for the colors making the vertices.

But, like Phong shading model where the calculation is done right in the fragment shader, what happens? How are the fragment pixels shaded? Say there are three vertices then is the fragment fully colored with the first color, fully with second and then with third and is the total median of the colors taken or something? How is the fragment shaded when the calculated within the fragment shader?

Upvotes: 4

Views: 3802

Answers (2)

Rabbid76
Rabbid76

Reputation: 210909

The vertex shader is executed once for each vertex. The fragment shader is executed once for each fragment. The outputs of the vertex shader are interpolated depending on the Barycentric coordinate of the fragment on the triangle primitive and that's the input to the fragment shader.
The input to the fragment shader is different for each fragment (because it is interpolated).

In you special case this means that, Normal and FragPos are different for each fragment. Each triangle has 3 corners. Normal and FragPos are computed for each corner of the triangle in the vertex shader. The attributes for the corners are interpolated for each fragment which is covered by the triangle and that interpolated vectors are the input to the fragment shader.
Since each fragment has a different input (Normal and FragPos) the comuted output (FragColor) is different for each fragment.
The output is just slightly different for neighboring fragments, because the input differs only slightly, too. That causes the smooth lighting.

Note, even if the normal vector (Normal) is a face normal (the same normal for the 3 vertices), then still FragPos is different.

Furthermore the spcular highlight (float spec = pow(max(dot(viewDir, reflectDir), 0.0),32)) is not a linear function. Thus the specular highlight can't be computed correctly by a linear interpolation. It has to be computed per fragment.
Actually there is a difference if Normal and FragPos are interpolated and result is computed in the fragment shader, in compare when result is computed in the vertex shader and is interpolate through the fragments.


The vertex attributes are the input to the vertex shader. The output of the vertex shader is interpolated (always) and the interpolated values are the input to the fragment shader (Rasterization). The output of the fragment shader is written to the framebuffer:

vertex attrtibutes -> vertex shader -> interpolation/rasterization -> fragment shader -> framebuffer.

So, there is a difference if you interpolate Normal and FragPos and compute result in the fragment shader or if you compute result in the vertex shader and interpolate result

For a further information about the rendering pipeline see Rendering Pipeline Overview.

Upvotes: 3

gkv311
gkv311

Reputation: 2982

The difference between Phong an Gouraud shading is that:

  • Gouraud averages colors. Color is computed based on vertex normal by Vertex Shader and then averaged between fragments of a single triangle based on the distance from each triangle vertex.
  • Phong averages normals. Color is computed by Fragment Shader based on averaging of 3 vertex normals of triangle passed through from Vertex Shader.

On high-polygonal mesh both give very close result, as dispersion of per-triangle colors become smaller.

On low-poly mesh, averaging shaded colors in Gouraud gives worse visual result, because averaging colors has close to none physical meaning.

Averaging normals within Phong shading simulates smooth surface properties, so that their averaging might be close or even match original analytical surface definition, leading to much more reasonable and smooth visual results.

The averaging is done not by Shader program itself, but by a fixed hardware functionality between Vertex and Fragment shader stages. So that when you compute color or pass-through normal / UV coordinates and similar in Vertex Shader, these values are interpolated by hardware between 3 vertices across all fragments inside triangle based on fragment barycentric coordinates.

The color computed within Fragment Shader is a final one (before applying Blending or Stencil test, which are also done by fixed hardware functionality). So that putting lighting computation inside Vertex of Fragment shader defines what will be interpolated and what is computed directly.

Upvotes: 6

Related Questions