Artifacts from fragment shading in OpenGL
Asked Answered
E

2

6

Trying to learn 3D programming, I am currently implementing a class which batch-renders cubes with OpenGL by pushing them to the GPU each frame. I tried to implement some crude lighting by 1) Sending each face normal to the GPU as part of the vertex attributes 2) Checking the direction of said normal and darken each fragment arbitrarily, like so:

Fragment Shader

#version 330

in vec2 ex_TexCoord;
in vec3 ex_Normal;
out vec4 out_Color;
uniform sampler2D textureSampler;

void main(void) {
  float lightAmplifier = 1.0;

  if (ex_Normal.z == 1.0) {
    lightAmplifier = .8;
  } else if (ex_Normal.x == 1.0) {
    lightAmplifier = .65;
  } else if (ex_Normal.x == -1.0) {
    lightAmplifier = .50;
  }

  out_Color = vec4(texture2D(textureSampler, ex_TexCoord).rgb * lightAmplifier, 1.0);
}

Resulting in this:

Screenshot

While not being very good at GLSL, my intuition says this is not correct behaviour. But a number google searches later, I'm still not sure what I'm doing wrong.

Envoy answered 17/3, 2018 at 13:55 Comment(1)
It could be floating point problem. Have you tried >=0.99 instead of ==1.0?Emeldaemelen
S
6

This is a floating point precision issue. Note the vertex coordinates are interpolated when for each fragment. It may always lead to issues, when comparing floating point numbers on equality.

On possible solution would be to use an epsilon (e.g. 0.01) and to change the comparison to < -0.99 and > 0.99:

if (ex_Normal.z > 0.99) {
    lightAmplifier = .8;
} else if (ex_Normal.x > 0.99) {
    lightAmplifier = .65;
} else if (ex_Normal.x < -0.99) {
    lightAmplifier = .50;
} 


Another possibility would be to use the flat interpolation qualifier, which causes the value not to be interpolated:

Vertex shader:

flat out vec3 ex_Normal;

Fragment shader:

flat in vec3 ex_Normal;
Shelbashelbi answered 17/3, 2018 at 15:37 Comment(0)
I
3

Rabbid76 is (probably) right about the erroneous appearance being a result of floating point accuracy/precision.

What I'd like to add is that setting a constant value based on testing an interpolated value is rarely a good idea (some algorithms do depend on it though, e.g. shadow mapping). Changing the test from ==1 to >=0.99 just puts the error at 0.99 intead of at 1.0. It is more likely you want to interpolate the value when it enters a certain range, e.g. by using mix.

Isolative answered 17/3, 2018 at 17:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.