【问题标题】:Edge artifacts after clipping using ortho projection使用正射投影裁剪后的边缘伪影
【发布时间】:2023-03-08 20:23:01
【问题描述】:

我成功地在 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";

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

这是我的正交投影矩阵

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

看起来就像 openGL 自动重新创建了一些三角形,所以它会在边缘(紫色线)周围制作人工制品。

有没有什么方法可以让这个边缘伪影消失,或者我需要重新定义我的索引?

提前感谢您的帮助。

【问题讨论】:

  • 你没有提供任何代码,我们怎么知道你在做什么?
  • 我只是放了一些代码。
  • 你能非常明确地说明你所看到的你不想要的东西吗?我们不知道您的意图是什么,所以我们不知道什么是“错误的”
  • 我不希望在投影矩阵中定义的最小 z 值之外有额外的三角形/线(紫色)。但不知何故,即使我认为我已经在我的投影矩阵中设置了限制,它仍然会插入一些东西
  • 您是否尝试过使用几何着色器并丢弃整个图元以防所有顶点的高度为 0?

标签: c++ opengl qt5.6


【解决方案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);

【讨论】:

    【解决方案2】:

    这些三角形是从哪里来的?

    很抱歉让您失望了,但剪辑应该是这样工作的。每个基元(三角形或线)的裁剪过程不会以二进制答案结束(即抛出或保留整个基元)。相反,图元被一个或多个图元替换,这些图元代表剪裁体积内原始图元的一部分。所以如果你有一个三角形ABC:

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

    A、B、C 的高度分别为 10、-1、-1,然后将其裁剪为高度 = 0,然后 OpenGL 将其替换为这个较小的三角形 Abc:

    A---b     B
      \ |
        c
    
    
              C
    

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

    你可以把它想象成通过提高剪裁平面的高度来提高一个假想的水位,OpenGL 会正确地重建与该水位相对应的海岸线。

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

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

    建议的解决方案

    如果您想丢弃在高度 0 的图元。

    如果您的硬件不支持几何着色器(并且高度图是动态的),那么您唯一的选择就是减少伪影。一种选择是用GL_LINE_STRIP 而不是glPolygonMode 画线(看起来你现在正在这样做)。它将避免在边缘生成那些长线,但仍会看到在顶点处相遇的那些短剪裁线段。

    原语重启索引

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

    【讨论】:

    • 感谢您对剪辑的解释。现在我使用GL_TRIANGLE_STRIP 代替GL_TRIANGLES 来绘制我的顶点。我还介绍了生成索引的方法。使用这种新方式,没有工件,但我在索引数组中使用了更多内存。
    • @zufryy:你为什么不试试原始的重启索引?它会像以前一样紧凑。
    • 老实说,现在我不知道如何使用原始重启索引。我会试着去看看,或者你对这个话题有一个简单的解释?
    • @zufryy: glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); 一次,然后在索引数组中使用-1 来终止前一个片段并开始一个新片段。例如。用GL_TRIANGLE_STRIP 渲染[0,1,2,3,-1,4,5,6,7] 将产生三角形[0,1,2][1,3,2][4,5,6][5,7,6]
    • 是的,与使用GL_TRIANGLES 的索引相比,它还可以节省大约一半的内存。谢谢大佬!!!
    猜你喜欢
    • 2011-10-14
    • 1970-01-01
    • 2017-07-08
    • 2014-10-14
    • 1970-01-01
    • 2021-05-30
    • 2021-07-15
    • 2013-10-19
    • 2014-08-16
    相关资源
    最近更新 更多