Артефакты ребер после обрезки с использованием ортопроекции

#c #opengl #qt5.6

#c #opengl #qt5.6

Вопрос:

Мне удалось сгенерировать карту высот с использованием VBO и IBO в OpenGL. Полная картина этих данных показана на рисунке ниже. На самом деле я хочу показать только данные с нечерным цветом. Я ставлю ноль в 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 ((rowamp;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 автоматически воссоздает некоторые треугольники, создавая артефакты по краю (фиолетовая линия).

масштабирование
введите описание изображения здесь

Есть ли какой-либо способ заставить эти артефакты ребер исчезнуть или мне нужно снова определить свои индексы?

Заранее благодарю вас за вашу помощь.

Комментарии:

1. Вы не предоставили никакого кода, как мы должны знать, что вы делаете?

2. Я просто вставил туда немного кода.

3. можете ли вы четко указать, что вы видите, чего не хотите? Мы не знаем, каковы ваши намерения, поэтому мы не знаем, что «неправильно»

4. Я не хочу, чтобы дополнительный треугольник / линия (фиолетовый) выходил за пределы моего минимального значения z, как я определяю в своей матрице проекции. Но каким-то образом это все еще интерполирует что-то, даже если я уже установил предел в своей матрице проекции

5. Вы пытались использовать геометрический шейдер и отбросить весь примитив в случае, если высота всех вершин равна 0?

Ответ №1:

Откуда берутся эти треугольники?

Извините, что разочаровываю вас, но именно так и должно работать отсечение. Процесс обрезки каждого примитива (треугольника или линии) не заканчивается двоичным ответом (т. Е. выбрасыванием или сохранением всего примитива). Вместо этого примитив заменяется одним или несколькими примитивами, которые представляют часть исходного примитива в объеме отсечения. Итак, если у вас есть треугольник ABC:

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

С высотами 10, -1, -1 из A, B, C соответственно, и вы обрезаете его на height = 0, затем OpenGL заменяет его на этот треугольник меньшего размера Abc:

 A---b     B
   |
    c


          C
  

С высотами 10, 0, 0 для A, b, c соответственно.

Вы можете представить это так, как будто, повышая высоту плоскости обрезки, вы повышаете воображаемый уровень воды, и OpenGL правильно восстанавливает береговую линию, соответствующую этому уровню воды.

подъем воды

Эти маленькие треугольники являются результатом этого желаемого поведения.

Смотрите постобработку вершин в wiki или главу об обрезке примитивов в спецификации OpenGL.

Предлагаемые решения)

Если вы хотите удалить целые ребра, которые пересекаются в вершине высотой <= 0, то вы можете либо сгенерировать геометрию в VBO, которая пропускает эти вершины, либо, если вы не можете этого сделать, потому что ваша карта высот динамическая, тогда используйте геометрический шейдер для прохождения только тех примитивов, которые полностью имеют высоту > 0.

Если ваше оборудование не поддерживает геометрические шейдеры (а карта высот динамическая), то ваш единственный выбор — уменьшить артефакт. Один из вариантов — нарисовать линии с помощью GL_LINE_STRIP вместо glPolygonMode (как, похоже, вы делаете сейчас). Это позволит избежать создания этих длинных линий по краям, но те короткие обрезанные сегменты, которые встречаются в вершинах, все равно будут видны.

Индекс перезапуска примитива

Это не связано с артефактом, но может пригодиться в будущем. Ваш текущий код, генерирующий индекс, похоже, перемещается по сетке взад-вперед. Я не знаю, зачем вы это делаете, но имейте в виду, что вы можете генерировать все последовательно и использовать GL_PRIMITIVE_RESTART для завершения одного GL_TRIANGLE_STRIP (или GL_LINE_STRIP ) и запуска нового из другой вершины в том же VBO.

Комментарии:

1. Спасибо за ваше объяснение по поводу обрезки. Теперь вместо использования GL_TRIANGLE_STRIP я использую GL_TRIANGLES для рисования своих вершин. Я также представляю способ генерации индексов. Благодаря этому новому способу артефактов нет, но я использую больше памяти в массиве индексов.

2. @zufryy: почему бы вам не попробовать простой перезапуск индекса? Это было бы так же компактно, как и раньше.

3. честно говоря, сейчас я понятия не имею, как использовать примитивный индекс перезапуска. Я попытаюсь разобраться или, может быть, у вас есть простое объяснение для этой темы?

4. @zufryy: glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); один раз, затем вы используете -1 в массиве индексов, чтобы завершить предыдущую полосу и начать новую. Например. рендеринг [0,1,2,3,-1,4,5,6,7] с GL_TRIANGLE_STRIP приведет к созданию треугольников [0,1,2] , [1,3,2] , [4,5,6] и [5,7,6] .

5. Да, это сработало, и это сэкономило около половины памяти по сравнению с использованием индексов для GL_TRIANGLES . Спасибо, приятель!!!

Ответ №2:

Как объяснил @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 ((rowamp;1) == 0 ) { // even rows
            for ( int col=0; col<numX; col   ) {
                if (vertices[row*numX   col][2] != 0 amp;amp; 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 amp;amp; 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 amp;amp; 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 amp;amp; 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 amp;amp; 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 amp;amp; 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);