PDA

View Full Version : Noisy shader output, but only when adding 0.5 to the texture coordinate



ksleet
12-18-2016, 12:33 AM
So I'm seeing some baffling behavior from my GLSL shaders. They do the bog-standard thing where you send in the texture coordinate as a vertex attribute to the vertex shader, and then pass it on through to the fragment shader, which then looks up the appropriate color in a bound texture. However, if I add 0.5 to the texture coordinate in the vertex shader, I see what looks like Z-fighting noise in the rendered output. No idea what might be causing this; I'm quite confident that there are not actually two triangles in the same place here. It also doesn't replicate if I add 0.49, or 0.51; just 0.5. Anyone ever seen something like this...?

Here's the vertex shader:


attribute vec3 i_position;
attribute vec2 i_texCoord;
attribute float i_heightScale;

varying vec2 texCoord;

uniform sampler2D i_heightmapTexture;
uniform float i_globalHeightScale;
uniform vec2 i_topLeft;
uniform vec2 i_bottomRight;

void main()
{
texCoord = i_topLeft + i_texCoord * (i_bottomRight - i_topLeft);

float heightmapSample = texture2D(i_heightmapTexture, texCoord).r;
float localHeight = heightmapSample * i_heightScale * i_globalHeightScale;

// Added this line to explicitly demonstrate the problem. I originally saw it when
// the input values above resulted in adding particular values to the texture coordinate.
texCoord.y = i_texCoord.y + 0.50;

gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(i_position.x, localHeight, i_position.z, 1.0);
}


And the fragment shader:


varying vec2 texCoord;

uniform sampler2D i_colormapTexture;

void main()
{
gl_FragColor = texture2D(i_colormapTexture, texCoord);
}

ksleet
12-18-2016, 02:14 PM
Additional fact: I'm using nearest-neighbor filtering for the noisy texture (i_colormapTexture.) I suspect that has something to do with it, as when I switch to linear filtering the problem disappears. I've run into this situation in the past where nearest-neighbor filtering is inconsistent across a triangle. Unfortuantely, I need to use nearest-neighbor since (at some point) the colormap texture is going to be used to index terrain types instead of directly color the surface.

GClements
12-19-2016, 07:20 AM
texCoord = i_topLeft + i_texCoord * (i_bottomRight - i_topLeft);



// Added this line to explicitly demonstrate the problem. I originally saw it when
// the input values above resulted in adding particular values to the texture coordinate.
texCoord.y = i_texCoord.y + 0.50;


Note that you aren't simply offsetting the coordinate by 0.5 relative to what it would have been, you're also omitting the scale factor (i_bottomRight - i_topLeft).

Noise in nearest-neighbour sampling is most noticeable if you end up sampling exactly at texel edges (or worse, corners), meaning that the effect of rounding error is maximised.

With a perspective projection and arbitrary view orientation, it's rather unlikely that you end up consistently sampling at texel edges, but it's quite possible with an orthographic projection and/or a lack of rotation.