3
\$\begingroup\$

I'm rendering a height map using shader-based OpenGL (3.3 to be precise). The height map data is from a grayscale bitmap (2D array of bytes). The dimension of the bitmap is 256 x 256.

With this data, being the Y value, I calculate X and Z as corners of uniformly distributed cells in a grid. I generate the vertices and upload it to a VBO. I generate indices and populate an IBO; indices are of type GLshort.

I've implemented a free roaming camera to roam around the terrain and verify its correctness. As I move around everything renders fine, except in some angles, particularly when viewing the terrain from above/afar, I see that some triangles in peaks of mountains go missing. In this position, if I vary the camera's position along its Z axis, I see the missing triangle are also varying. When I go closer to the peak, the error goes away and everything is nice and whole.

Culling

I've read other similar questions here, which mainly suggest that it could be because those triangles are deduced as back facing and thus may disappear when facet culling is enabled. To rule that case out, I tried glDisable(GL_CULL_FACE) in vain.

Z fighting

I thought of this issue too, but it doesn't make sense. Z fighting happens when two fragments have the same depth buffer value, but the triangles appearing in place of the missing ones (in a slightly different dull colour; see image below) are behind the missing ones and not at the same Z and thus shouldn't have this problem. In either case, I tried enabling and disabling depth test to be sure, but to no avail.

Floating-point

Worried about floating point issues, I make sure that the vertices of the terrain are distributed around the origin i.e. if each cell is a square of length c, then both X and Z values of vertices are distributed equally around 0 e.g. X doesn't vary between 0 to 256 but from -128 to 128, assuming a per cell dimension to be 1 unit.

Draw

Other than those I tried changing the way I give draw calls to GL: glDrawElements with GL_TRIANGLES, glDrawElementBaseVertex and glMultiDrawElementsBaseVertex with GL_TRIANGLE_STRIP didn't change the the situation too.

I tried searching on the internet for an explanation but I'm at a loss there too, particularly when one doesn't know the keyword to search for. This should be happening fairly commonly in serious games since they all have terrains of some kind. Is there a proper name for this, and a solution?

Screen 1 Screen 2

\$\endgroup\$
4
  • 1
    \$\begingroup\$ it could be Z-fighting (depth buffer conflict). Z buffer usually has quite low depth resolution, so if your far plane is far, and you are far away from it, the faraway bins of the depth buffer will include a lot of space. You could try turning backface cull on; increasing depth buffer resolution; or making the far plane closer. \$\endgroup\$
    – Qwerty
    Commented Nov 16, 2014 at 9:13
  • \$\begingroup\$ Hey, I tried your suggestion and it seems to work! My near and far were 0.001f and 5000.0f, changing them to 100.0f and 2000.0f makes the issue vanish. Could you please post this as an answer and some material for me to read on this to understand the reason clearly? \$\endgroup\$
    – legends2k
    Commented Nov 16, 2014 at 9:35
  • \$\begingroup\$ @Qwerty I was able to find a related question here with your input. Related: gamedev.stackexchange.com/questions/82950/…. \$\endgroup\$
    – legends2k
    Commented Nov 16, 2014 at 9:52
  • \$\begingroup\$ This tutorial explains the exact same issue and gives a decent solution. \$\endgroup\$
    – legends2k
    Commented Nov 30, 2014 at 7:39

1 Answer 1

6
\$\begingroup\$

so, to rework from comments: this is Z-fighting. The math is very well explained here: http://chaosinmotion.com/blog/?p=555, and the ways to solve it here: https://www.opengl.org/wiki/Depth_Buffer_Precision, but the gist is that Z-buffer is discrete, non-linear, and depends on the ratio of farplane/nearplane.

  • discrete: the distance between near and far plane is sliced into layers. if two overlapping fragments (would-be pixels) fall in the same Z-layer, it's up to chance as to which one will be actually drawn. the number of layers depends on how many bits per pixel is allocated to the depth buffer. In extreme case, if the depth buffer is 2 bits per pixel, there are only 4 slices.

  • non-linear: far-away slices are 'thicker' than the nearby slices. so the further away you look, the more chance there is of Z-fighting

  • depending on the ratio: you say you have near at 0.001f and far at 5000.0f - ratio of 5 million. the suggested ratio is no more than 30k. one easy way to fix it is to move the near to 0.1f: not a huge loss of scenery, but a great increase of depth resolution.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Thanks for the clear explanation and the excellent links! \$\endgroup\$
    – legends2k
    Commented Nov 17, 2014 at 12:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .