使用正投影剪裁后的边缘伪影

时间:2016-10-19 05:08:40

标签: c++ opengl qt5.6

我成功地在openGL中使用VBO和IBO生成高度图。该数据的完整图片如下图所示。我想要真正展示的只是非黑色的数据。当颜色为黑色时,我将z值设为零。

这是我生成索引的代码

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));
            }
        }
    }
}

我的着色器代码

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

不幸的是,在使用我的投影矩阵(正交)剪辑z值之后。我仍然在边缘得到一些文物,如下图所示。

这是我的正投影矩阵

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

After Clipping

看起来像openGL会自动重新创建一些三角形,因此它会在边缘(紫色线条)周围形成artifac。

zoom enter image description here

是否有任何方法可以使此边缘工件消失或者我需要再次定义索引?

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

这些三角形来自何处?

很抱歉让你失望,但这就是裁剪应该起作用的方式。每个基元(三角形或线形)的剪切过程不以二进制答案结束(即抛出或保留整个基元)。相反,基元被一个或多个基元替换,基元表示限幅体积内原始基元的一部分。所以如果你有一个三角形ABC:

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

分别使用A,B,C的高度10,-1,-1,并将其与height = 0进行剪裁,然后OpenGL用这个较小的三角形Abc替换它:

A---b     B
  \ |
    c


          C

分别为A,b,c的高度10,0,0。

您可以将其想象为通过提高剪切平面高度来提升虚拟水位,并且OpenGL正确地重建与该水位相对应的岸线。

raising water

这些小三角形是期望的行为的结果。

请参阅wiki中的Vertex Post-Processing或OpenGL规范中的Primitive Clipping章节。

提议的解决方案

如果你想扔掉在高度 gt的基元。 0

如果您的硬件不支持几何着色器(并且高度图是动态的),那么您唯一的选择是减少工件。一种选择是使用GL_LINE_STRIP而不是glPolygonMode绘制线条(因为您现在正在做的事情)。它将避免在边缘处生成那些长线,但仍会看到在顶点处相遇的那些短截线段。

原始重启索引

这与神器无关,但它可能在将来派上用场。您当前的索引生成代码似乎以来回的方式遍历网格。我不知道你为什么要这样做,但请记住,你可以按顺序生成所有内容,并使用GL_PRIMITIVE_RESTART结束一个GL_TRIANGLE_STRIP(或GL_LINE_STRIP)并开始一个新的一个来自同一个VBO 内的不同顶点

答案 1 :(得分:1)

正如@ybungalobill在他/她的回答中所解释的那样,工件是openGL行为并且很难被改变。所以我的解决方案是创建新程序来创建索引。这是代码

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();
} 

绘制时也会输入此代码

glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, 0);
glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);