I'm trying to implement ambient occlusion on a voxel-based mesh and get these flickering white pixels at the edges of faces:
Here is my fragment shader:
#version 120
varying vec4 color;
varying vec4 normal;
void main(void)
{
float light = normal.w + max(0.15*dot(normal.xyz, vec3(1,1,1)), 0.0);
gl_FragColor = vec4(color.xyz * light, 1.0);
}
If I remove the light
from the gl_FragColor
vec4
then the artifact disappears. The light
value is calculated from the ambient occlusion value (normal.w
) and a specular component. It seems like it's the specular that's causing the problem. Why would corners and edges suddenly flash like this? The white pixels appear to shimmer as the mesh is rotated. But on larger surfaces, the specular highlights appear normal and follow the light source rather than flicker on and off.
Now that you mention it, if you followed the normal solution for T-Junction elimination, which is to insert vertices at T-Junctions you would basically undo the benefits of greedy meshing. I see this has already been discussed here with no actual solution proposed. Apparently the argument there was that the issue doesn't prop up enough on most hardware to warrant any further investigation.
In your case, it almost seems that the issue does not pop up during the actual rasterization of polygon edges (T-Junction errors), but rather when you try to compute values in your fragment shader that rely on per-vertex interpolation. I see that you are clearing your color buffer to red, so it is even less likely that these are sub-pixel T-Junction errors during rasterization in that case. Upon closer inspection, I notice some discontinuities along your diagonal triangle edges (the normals seem to be flipped for half of your face). Perhaps the issue is actually related to large discrepancies in some input vertex attribute. I'd try to fix-up the lighting to produce smooth results across the entire face first, maybe whatever is causing that is also causing the issues at T-Junctions.
In fact, would it be possible to include your vertex shader in the question? I am curious to see how normal.w
is computed.
I ported your code to OS X (harder than you'd think :P), with the same results:
OpenGL renderer string: NVIDIA GeForce GT 330M OpenGL Engine OpenGL version string: 2.1 NVIDIA-1.6.36 OpenGL shading language version string: 1.20
After making the following changes to the vertex shader:
//normal = v_normal; normal = vec4 (normalize (v_normal.xyz), v_normal.w);
and fragment shader:
//float light = normal.w * max (0.15*dot(normal.xyz, vec3 (1,1,1)), 0.0); float light = normal.w * max (1.5*dot(normal.xyz, vec3 (1,1,1)), 0.0);
The sparklies disappear and this is the result:
Your ambient occlusion term still seems to be reversed for half of your triangulated faces, however.