Я пишу 3D-игру с использованием OpenGL. У меня проблема с сортировкой при рендеринге полупрозрачных треугольников. Я знаю, что их нужно сортировать, но как? Я не хочу использовать деревья BSP (если я хочу изменить положение объекта, мне нужно перестроить дерево) и алгоритмы OIT (дорогая производительность). Я хочу отсортировать их по «покрытию».
У меня есть два полупрозрачных треугольника, и я использую перспективную камеру, чтобы проецировать их на экран.
Область просмотра: 0, 0, 1280, 720
Например
[ПРАВИЛЬНАЯ СОРТИРОВКА] черный треугольник закрывает зеленый треугольник.
[НЕПРАВИЛЬНАЯ СОРТИРОВКА] зеленый треугольник закрывает черный треугольник.
Треугольники на изображениях непрозрачны, чтобы отчетливо видеть артефакты сортировки.
Мое решение этой проблемы
Преобразуйте вершины этих треугольников в координаты экранного пространства и сравните их, интерполируя координату z, НО на моих изображениях вы можете видеть, что одна координата черного треугольника находится вне области просмотра и поэтому эта координата странная (примерно так: -2896; 1423 ; 1.169), и я не могу интерполировать координату z на черном треугольнике.
Как я преобразовываюсь в координаты экранного пространства
- Преобразование вершин треугольника с помощью матрицы MVP
- Выполнить перспективное деление
- Превратить в экранное пространство
Преобразование по матрице 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);
Что я делаю неправильно? Зачем координировать то, что вне области просмотра странно? Как получить правильную координату вне области просмотра?
--- РЕДАКТИРОВАТЬ ---
Выяснил, что если одна координата треугольника за пределами области просмотра, то треугольник надо разделить на два.
Но как разделить треугольник на два, используя координаты пространства отсечения и плоскости отсечения?