3

I success to generate the height map using VBO and IBO in openGL. The full picture of this data is shown in the figure below. What I want really show is only the data with non-black color. I put zero in z-value when the color is black.

Here is my code to generated the indexes

void triangle::getIndices(QVector<double> minmaxX_, QVector<double> minmaxY_)
{
    indices.clear();
    int numY = round((minmaxY_[1] - minmaxY_[0]) / minmaxY_[2]) + 1;
    int numX = round((minmaxX_[1] - minmaxX_[0]) / minmaxX_[2]) + 1;
    for (int row=0; row<numY-1; row++) {
        if ((row&1) == 0 ) { // even rows
            for ( int col=0; col<numX; col++ ) {
                indices.append(col + row*numX);
                indices.append(col + (row + 1)*numX);
            }
        }
        else {
            for ( int col=numX-1; col>=0; col-- ) {
                indices.append(col + (row*numX));
                indices.append(col + ((row + 1)*numX));
            }
        }
    }
}

My Shader Code

const char* const frgshdr_source =
        "uniform const float colorSize;\n"
        "uniform vec3 colorTable[512];"
        "varying float height;\n"
        "uniform float heightSize;\n"
        "uniform float heightMin;\n"
        "void main() {\n"
        "   //vec3 colorTable2[int(colorSize)+1] = colorTable;\n"
        "   float h = (height - heightMin)/heightSize;\n"
        "   if (h < 0.0f || h > 1.0f) {\n"
        "       gl_FragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);}\n"
        "   else {"
        "       int i = 0;\n"
        "       while (h >= float(i + 1)/colorSize) {\n"
        "           i += 1;}\n"
        "       vec3 base = mix(colorTable[i], colorTable[i+1], colorSize*(h - (float(i)/colorSize)));\n"
        "       gl_FragColor = vec4(base, 1.0f);}\n"
        "}\n";

Full Data

Unfortunately after I clip the z-value using my projection matrix (orthographic). I still get some artifacts on the edge like in the picture below.

here is my orthographic projection matrix

m_projection.ortho( minX, maxX, minY, maxY, minZ, maxZ);

After Clipping

Look's like openGL recreate some triangles automatically so it makes artifacs around the edge (purple line).

zoom enter image description here

Is there any method to make this edge artifacts disappear or I need to define my indexes again ?

Thank you in advance for your help.

zufryy
  • 177
  • 2
  • 10
  • 4
    You didn't provide any code, how are we supposed to know what you're doing? – xaxxon Oct 19 '16 at 05:13
  • I just put some code there. – zufryy Oct 19 '16 at 05:26
  • 1
    can you be very explicit about what you are seeing that you don't want? We don't know what your intent is, so we don't know what is 'wrong' – xaxxon Oct 19 '16 at 05:29
  • I don't want extras triangle / line (purple) outside my minimum z value as I define in my projection matrix. But somehow it still interpolate something even thought I already set the limit in my projection matrix – zufryy Oct 19 '16 at 05:36
  • Have you tried to use a geometry shader and discard the whole primitive in case all vertices have a height of 0? – thokra Oct 19 '16 at 09:34
  • @thokra : I tried to insert this in my geometry shader and it not work. `"if (height > 0.0f) {\n"` `" gl_Position = mvpMatrix*vec4(posAttr, 1.0f);\n" ` Now I'm trying to reproduce my index with conditional function. And see if its work – zufryy Oct 19 '16 at 11:19

2 Answers2

3

Where those triangles come from?

Sorry to disappoint you, but this is how clipping is supposed to work. The clipping process of each primitive (triangle or line) does not end in a binary answer (i.e. throwing or retaining the entire primitive). Instead the primitive is replaced with one or more primitives which represent the part of the original primitive within the clipping volume. So if you have a triangle ABC:

A---------B
  \       |
    \     |
      \   |
        \ |
          C

With heights 10, -1, -1 of A, B, C respectively, and you clip it against height = 0, then OpenGL replaces it with this smaller triangle Abc:

A---b     B
  \ |
    c


          C

With heights 10, 0, 0 of A, b, c respectively.

You can think of it as if by raising the clipping plane height you raise an imaginary water-level, and OpenGL correctly reconstructs the shore-line corresponding to that water-level.

raising water

Those small triangles are the result of this desired behavior.

See Vertex Post-Processing in the wiki, or the Primitive Clipping chapter in the OpenGL spec.

Proposed solution(s)

If you want to throw away entire edges that intersect at a vertex of height <= 0, then you can either generate a geometry in the VBO that skips those vertices, or if you cannot do that because your height-map is dynamic, then use a geometry shader to pass-through only those primitives which are entirely at height > 0.

If your hardware does not support geometry shaders (and heightmap is dynamic), then your only choice is to reduce the artifact. One option is to draw the lines with GL_LINE_STRIP instead of glPolygonMode (as it appears you're doing now). It will avoid generating those long lines at the edges, but those short clipped segments meeting at the vertices will still be seen.

Primitive restart index

This is unrelated to the artifact, but it may come in handy in the future. Your current index generating code seems to traverse the grid in a back-and-forth fashion. I don't know why you do this, but keep in mind that you can generate everything in sequence and use GL_PRIMITIVE_RESTART to end one GL_TRIANGLE_STRIP (or GL_LINE_STRIP) and start a new one from a different vertex within the same VBO.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Thank for your explanation about the clipping. Now instead using `GL_TRIANGLE_STRIP`, I use `GL_TRIANGLES` to draw my vertices. I also introduce the way to generating the indexes. With this new way, there are no artifacts but I use more memory in the indexes array. – zufryy Oct 21 '16 at 01:52
  • 1
    @zufryy: why won't you try a primitive restart index? It would be as compact as before. – Yakov Galka Oct 21 '16 at 06:18
  • honestly now I have no idea how to use the primitive restart index. I'll try to look it out or maybe you have a simple explanation for this topic ? – zufryy Oct 21 '16 at 06:53
  • 1
    @zufryy: `glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);` once, then you use `-1` in the index array to terminate the previous strip and start a new one. E.g. rendering `[0,1,2,3,-1,4,5,6,7]` with `GL_TRIANGLE_STRIP` will produce the triangles `[0,1,2]`, `[1,3,2]`, `[4,5,6]` and `[5,7,6]`. – Yakov Galka Oct 21 '16 at 07:01
  • Yes it worked also it save around half of memory compare to use indexes for `GL_TRIANGLES`. Thank mate !!! – zufryy Oct 21 '16 at 10:06
1

As @ybungalobill explained in his/her answer, the artifacts is the openGL behavior and it's hard to be changed. So my solution is make the new procedure to create the indexes. And this is the code

void triangle::getIndices(QVector<double> minmaxX_, QVector<double> minmaxY_)
{
    indices.clear();
    int numY = round((minmaxY_[1] - minmaxY_[0]) / minmaxY_[2]) + 1;
    int numX = round((minmaxX_[1] - minmaxX_[0]) / minmaxX_[2]) + 1;

    for (int row = 0; row < numY - 1; row++) {
        if ((row&1) == 0 ) { // even rows
            for ( int col=0; col<numX; col++ ) {
                if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] != 0) {
                    indices.append(row*numX + col);
                    indices.append((row + 1)*numX + col);
                }
                else if (vertices[row*numX + col][2] == 0 && vertices[(row+1)*numX + col][2] != 0) {
                    indices.append((row + 1)*numX + col);
                    indices.append((row + 1)*numX + col);
                }
                else if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] == 0) {
                    indices.append(row*numX + col);
                    indices.append(row*numX + col);
                }
                else {
                    indices.append(-1);
                }
            }
        }
        else {
            for ( int col=0; col<numX; col++ ) {
                if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] != 0) {
                    indices.append(row*numX + col);
                    indices.append((row + 1)*numX + col);
                }
                else if (vertices[row*numX + col][2] == 0 && vertices[(row+1)*numX + col][2] != 0) {
                    indices.append((row + 1)*numX + col);
                    indices.append((row + 1)*numX + col);
                }
                else if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] == 0) {
                    indices.append(row*numX + col);
                    indices.append(row*numX + col);
                }
                else {
                    indices.append(-1);
                }
            }
        }
    }

    qDebug() << indices.size();
} 

Also put this code when draw

glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, 0);
glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
zufryy
  • 177
  • 2
  • 10