Как сортировать полупрозрачные треугольники в OpenGL?

Я пишу 3D-игру с использованием OpenGL. У меня проблема с сортировкой при рендеринге полупрозрачных треугольников. Я знаю, что их нужно сортировать, но как? Я не хочу использовать деревья BSP (если я хочу изменить положение объекта, мне нужно перестроить дерево) и алгоритмы OIT (дорогая производительность). Я хочу отсортировать их по «покрытию».

У меня есть два полупрозрачных треугольника, и я использую перспективную камеру, чтобы проецировать их на экран.

Область просмотра: 0, 0, 1280, 720

Например

[ПРАВИЛЬНАЯ СОРТИРОВКА] черный треугольник закрывает зеленый треугольник.

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

[НЕПРАВИЛЬНАЯ СОРТИРОВКА] зеленый треугольник закрывает черный треугольник.

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

Треугольники на изображениях непрозрачны, чтобы отчетливо видеть артефакты сортировки.


Мое решение этой проблемы

Преобразуйте вершины этих треугольников в координаты экранного пространства и сравните их, интерполируя координату z, НО на моих изображениях вы можете видеть, что одна координата черного треугольника находится вне области просмотра и поэтому эта координата странная (примерно так: -2896; 1423 ; 1.169), и я не могу интерполировать координату z на черном треугольнике.

Как я преобразовываюсь в координаты экранного пространства

  1. Преобразование вершин треугольника с помощью матрицы MVP
  2. Выполнить перспективное деление
  3. Превратить в экранное пространство

Преобразование по матрице MVP

public Vector4f transform(Vector4f vector) {
    float x = m00 * vector.x + m10 * vector.y + m20 * vector.z + m30 * vector.w;
    float y = m01 * vector.x + m11 * vector.y + m21 * vector.z + m31 * vector.w;
    float z = m02 * vector.x + m12 * vector.y + m22 * vector.z + m32 * vector.w;
    float w = m03 * vector.x + m13 * vector.y + m23 * vector.z + m33 * vector.w;

    return new Vector4f(x, y, z, w);
}

Разделение перспективы

public Vector3f perspectiveDivide() {
    float wInverse = 1.0f / w;
    return new Vector3f(x * wInverse, y * wInverse, z * wInverse);
}

Превратить в экранное пространство

public void toScreenCoords(int width, int height) {
    x = (x * 0.5f + 0.5f) * width;
    y = (y * 0.5f + 0.5f) * height;
    z = (z + 1.0f) * 0.5f;
}

Как я это делаю

Vector4f clipspace = mvp.transform(triangle_vertex);
Vector3f ndc = clipspace.perspectiveDivide();
Vector3f screenspace = ndc.toScreenCoords(1280, 720);

Что я делаю неправильно? Зачем координировать то, что вне области просмотра странно? Как получить правильную координату вне области просмотра?


--- РЕДАКТИРОВАТЬ ---

Выяснил, что если одна координата треугольника за пределами области просмотра, то треугольник надо разделить на два.

Но как разделить треугольник на два, используя координаты пространства отсечения и плоскости отсечения?


person a7292969    schedule 15.07.2018    source источник
comment
Странные координаты, вероятно, вызваны вершиной, которая находится за камерой. Ваша главная проблема, однако, заключается в том, что треугольники не всегда можно отсортировать (представьте себе три чередующихся треугольника; в этом случае вам нужно разбить один из них). Структуры данных, такие как kd-деревья или BSP-деревья, позволяют выполнять эти разбиения, когда это необходимо. Почему ты не хочешь их использовать?   -  person Nico Schertler    schedule 15.07.2018
comment
Существует несколько стандартных алгоритмов отсечения. Но я действительно не понимаю ваш подход, особенно то, что Преобразует вершины этих треугольников в координаты экранного пространства и сравнивает их путем интерполяции координаты z. значит? Для каких точек вы интерполируете z?   -  person derhass    schedule 15.07.2018
comment
@derhass Чтобы получить точки (x, y) для интерполяции z, я ищу пересечение двух линий, одной из первого треугольника и второй из зеленого. Затем я интерполирую z из первого треугольника и второго треугольника по этой точке.   -  person a7292969    schedule 16.07.2018
comment
@NicoSchertler Я не хочу использовать BSP-дерево, потому что, если я хочу изменить положение объекта, мне нужно перестроить это дерево.   -  person a7292969    schedule 16.07.2018
comment
Я ищу пересечение между двумя линиями, одной из первого треугольника и второй из зеленого. Затем я интерполирую z из первого треугольника и второго треугольника по этой точке. Этот алгоритм не имеет ни малейшего смысла. Кажется, вы хотите использовать 2D-проекцию для этих линий и просто выполнить тест глубины в одной точке, которая покрыта обоими треугольниками. Но это будет работать только для случаев, когда треугольники не будут пересекаться, но если это можно предположить, вам не понадобится сложный алгоритм для их проецирования и обрезки в первую очередь.   -  person derhass    schedule 16.07.2018
comment
@derhass Я предполагаю, что треугольники не пересекаются.   -  person a7292969    schedule 16.07.2018


Ответы (1)


Быстрое и простое решение для правильной сортировки (полупрозрачных) треугольников

«Фальшивая сортировка проекций», как я это называю. Если вы можете предположить, что треугольники не будут пересекаться, то вы можете просто проверить, пересекает ли треугольник (черный или зеленый) тетраэдр (координаты черного или зеленого треугольника и положение камеры).


Пример

Координаты первого треугольника:

0.0, 0.0, 5.0
0.0, 5.0, 5.0
5.0, 5.0, 5.0

Координаты второго треугольника:

0.0, 0.0, 5.0
5.0, 0.0, 5.0
5.0, 0.0, 5.0

Положение камеры

1.15, 5.8, 5.5

Тогда координатами тетраэдра будут координаты треугольника (например, первого) и положения камеры.

0.0,  0.0, 5.0  // First coordinate from the first triangle
0.0,  5.0, 5.0  // Second coordinate from the first triangle
5.0,  5.0, 5.0  // Third coordinate from the first triangle
1.15, 5.8, 5.5  // Camera position

Последнее, что вам нужно сделать, это проверить, пересекает ли второй треугольник тетраэдр. Если второй треугольник пересекается, то он покрывает первый треугольник. Если вы используете координаты из второго треугольника для создания тетраэдра, то вам нужно проверить первый треугольник на пересечение, а не второй.


Примечание

Не используйте TreeSet или TreeMap из Java для сравнения треугольников с использованием «сортировки поддельных проекций», это может привести к неправильной сортировке.

person a7292969    schedule 16.07.2018