Why is basic specular shading fluid, and not jagged?

277 Views Asked by At

Simple question, I just got my first specular shader working, and looking over the math, I cant help to think that the angle between each edge should cause the "specularity" to spike/become jagged. But its entirely fluid/spherical.

The idea is to calculate the angle off the vertice-normal, but there are only so many of these, and still the "specular shade" turns out perfectly even.

I cant see how the gpu knows the angle of the fragment based off of the vertice normal alone.

enter image description here

edit: vert shader

#version 400 core

layout ( location = 0 ) in vec3 vertex_position;
layout ( location = 2 ) in vec2 tex_cord;
layout ( location = 3 ) in vec3 vertex_normal;

uniform mat4 transform; //identity matrix
uniform mat3 lmodelmat; //inverse rotation

out vec2 UV;
out vec3 normal;

void main()
{
  UV=tex_cord;
  normal=normalize(vertex_normal*lmodelmat);  //normalize to keep brightness

  gl_Position=transform*vec4(vertex_position,1.0);
}

and frag

#version 400 core

in vec2 UV;
in vec3 normal;

uniform sampler2D mysampler;
uniform vec3 lightpos; //lights direction

out vec4 frag_colour;

in vec3 vert2cam; //specular test

void main()
{
  //skip invis frags
  vec4 alphatest=texture(mysampler,UV);
  if(alphatest.a<0.00001)discard; 

  //diffuse'ing fragment
  float diffuse=max(0.1,dot(normal,lightpos));

  //specular'izing fragment
  vec3 lpnorm=normalize(lightpos);  //vector from fragment to light
  vec3 reflection=normalize(reflect(-lpnorm,normal)); //reflection vector
  float specularity=max(0,dot(lpnorm,reflection));
  specularity=pow(specularity,50);

  frag_colour=alphatest*diffuse+specularity;
}

Answer: Interpolation

This will, for the renderer, equate as an averaged curve, and not a jagged edge (flat shading)

1

There are 1 best solutions below

4
On BEST ANSWER

Without code .etc. it is hard to precisely answer your question but assuming a simple vector shader -> fragment shader pipeline. The vector shader will be run for each vertex. It will set typically set parameters marked 'varying' (e.g. texture coordinates).

Every 3 vertices will be grouped to form a polygon and the fragment shader run to determine the color of each point within the polygon. The 'varying' parameters set by the vertex shader will be interpolated based on the distance of the fragment from the 3 edges of the polygon (See: Barycentric interpolation).

Hence for example:

gl_FragColor = texture2D(myUniformSampler, vec2(myTextureCoord.s,myTextureCoord.t));

Will sample the texture correctly for each pixel. Assuming you're using per-fragment lighting, the values are probably being interpolated for each fragment shader from the values you set in your vertex shader. If you set the same normal for each edge you'll get a different effect.

Edit (Based on the code you added):

out vec2 UV;
out vec3 normal;
out vec3 color;

Are set per vertex in your vertex shader. Every three vertices defines a polygon. The fragment shader is then run for each point (e.g. pixel) within the polygon to determine the color .etc. of each point.

The values of these parameters:

in vec3 color; /// <<-- You don't seem to be actually using this
in vec2 UV;
in vec3 normal;

in the fragment shader are interpolated based on the distance of the point on the polygon being 'drawn' from each vertex (See: Barycentric interpolation). Hence the normal varies between the vertices defined by your vertex shader.

If for a given polygon defined by three vertices you set the normals to all be facing in the same direction, you will get a different effect.