8
votes

I am rendering a point based terrain from loaded heightmap data - but the points change their texturing depending on where the camera position is. To demonstrate the bug (and the fact that this isnt occuring from a z-buffering problem) I have taken screenshots with the points rendered at a fixed 5 pixel size from very slightly different camera positions (same angle), shown bellow:

PS: The images are large enough if you drag them into a new tab, didn't realise stack would scale them down this much.

State 1: State 1 image

State 2: State 2 image

The code to generate points is relatively simple so I'm posting this merely to rule out the option - mapArray is a single dimensional float array and copied to a VBO:

for(j = 0; j < mHeight; j++)
{
    for(i = 0; i < mWidth; i++)
    {
        height = bitmapImage[k];

        mapArray[k++] = 5 * i;
        mapArray[k++] = height;
        mapArray[k++] = 5 * j;
    }
}

I find it more likely that I need to adjust my fragment shader because I'm not great with shaders- although I'm unsure where I could have gone wrong with such simple code and guess it's probably just not fit for purpose (with point based rendering). Bellow is my frag shader:

in varying vec2 TexCoordA;
uniform sampler2D myTextureSampler;

void main(){
    gl_FragColor = texture2D(myTextureSampler, TexCoordA.st) * gl_Color;
}

Edit (requested info): OpenGL version 4.4 no texture flags used.

TexCoordA is passed into the shader directly from my Vertex shader with no alterations at all. Self calculated UV's using this:

float* UVs = new float[mNumberPoints * 2];
    k = 0; 
    for(j = 0; j < mHeight; j++)
    {
        for(i = 0; i < mWidth; i++)
        {
            UVs[k++] = (1.0f/(float)mWidth) * i;
            UVs[k++] = (1.0f/(float)mHeight) * j;
        }
    }
2
Aside from the warped aspect ratio, what exactly is supposed to be different between the two images? - Andon M. Coleman
If you look in the highlighted red circle area; some of points in one image change their colour compared to the second image - directly taken from a texture. UV's dont change, point position doesn't change. The only thing that move's is the camera- and it seems to affect the texture sampliing. - jProg2015
It is occurring because the camera is moving. Consider the (bottom) diagram here and what happens when you shift the position in sub-pixel increments. If your coverage area included the entire pixel, this shift would not be nearly as noticeable. - Andon M. Coleman
Perspective texture correction (division by Q) occurs automatically. That is not even the issue here, to be honest. The issue is that the coverage area in that diagram will shift by 1 whole pixel if you move the vertex that generated the point even slightly upwards in screen-space (the bottom X at (2.5, 0.5) will drop out). The center might not cross a pixel boundary, but the coverage area will. - Andon M. Coleman
@Tom Burbeck: can you please update the question with: the vertex shader (i'm interested in TexCoordA calculus), the loading of the texture assigned to myTextureSampler uniform and the sampling flags used for that texture(if none used please let me know the opengl version) - Raxvan

2 Answers

0
votes

Just a guess: How are your point rendering parameters set? Perhaps the distance attenuation (GL_POINT_DISTANCE_ATTENUATION ) along with GL_POINT_SIZE_MIN and GL_POINT_SIZE_MAX are causing different fragment sizes depending on camera position. On the other hand I think I remember that when using a vertex shader these functionality is disabled and the vertex shader must decide about the size. I did it once by using

//point size calculation based on z-value as done by distance attenuation
float psFactor = sqrt( 1.0 / (pointParam[0] + pointParam[1] * camDist + pointParam[2] * camDist * camDist) );
gl_PointSize   = pointParam[3] * psFactor; 

where pointParam holds the three coefficients and the min point size:

uniform vec4 pointParam;   // parameters for point size calculation [a b c min]

You may play around by setting your point size in the vertex shader directly with gl_PointSize = [value].

0
votes

This looks just like a subpixel accurate texture mapping side-effect. The problem with texture mapping implementation is that it needs to interpolate the texture coordinates on the actual rasterized pixels (fragments). When your camera is moving, the roundoff error from real position to the integer pixel position affects texture mapping, and is normally required for jitter-free animation (otherwise all the textures would jump by seemingly random subpixel amounts as the camera moves. There was a great tutorial on this topic by Paul Nettle.

You can try to fix this by not sampling texel corners but trying to sample texel centers (add half size of the texel to your point texture coordinates).

Another thing you can try is to compensate for the subpixel accurate rendering by calculating the difference between the rasterized integer coordinate (which you need to calculate yourself in a shader) and the real position. That could be enough to make the sampled texels more stable.

Finally, size matters. If your texture is large, the errors in the interpolation of the finite-precision texture coordinates can introduce these kinds of artifacts. Why not use GL_TEXTURE_2D_ARRAY with a separate layer for each color tile? You could also clamp the S and T texcoords to edge of the texture to avoid this more elegantly.