Объединение нескольких сегментов линий
-
20-09-2019 - |
Вопрос
Моя программа использует Pyopengl (так что это Python) с psyco.
У меня есть около 21 000 сегментов линий, которые мне нужно рендеринг в каждом кадре моего рендеринга (если пользователь не увеличивает, в этом случае сегменты линий отключены и вообще не отправляются на карту). В настоящее время это занимает около 1,5 секунды каждый кадр. Этого недостаточно, поэтому я ищу способы уменьшить количество отдельных линейных сегментов.
Я полагаю, что будут случаи, когда несколько сегментов линий могут быть объединены в одну большую линию, но я, честно говоря, даже не знаю, с чего начать с этого. У меня есть начальная точка и конечная точка каждой линии, хранящейся, так что это может помочь. Обратите внимание, что я могу взять столько времени, сколько мне нужно в стартапе, и использование памяти не слишком озабочен.
Любые идеи были бы очень оценены.
Решение
Это почти наверняка накладные расходы всех непосредственных вызовов функции режима, которые убивают вашу производительность. Я бы сделал следующее.
Не используйте GL_LINE_STRIPS
, используйте один список GL_LINES
Вместо этого они могут быть сделаны за один раз.
Использовать glDrawArrays
Вместо немедленного рендеринга режима:
float* coordinates = {....}; //x and y coordinate pairs for all line segments
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(float), coordinates);
glDrawArrays(GL_LINES, 0, 2 * linecount);
glDisableClientState(GL_VERTEX_ARRAY);
(Для еще лучшей производительности вы можете хранить буфер вершины в том, что называется буферным объектом вершины, но с самого начала это должно быть хорошо)
Последнее, что если вы делаете отбирательную работу по линии, вероятно, быстрее просто пропустить его и отправить все строки в графический процессор.
Другие советы
Сегменты 20K не так уж и много. Кроме того, вам повезет, когда вы сможете объединить 10-100 линий на кадр, поэтому ускорение этой оптимизацией будет пренебрежным. Процесс рендеринга, вероятно, медленный, потому что вы создаете модель снова и снова. Использовать glNewList()
Чтобы сохранить все команды рендеринга в списке рендеринга GL на карте, а затем просто выпустите glCallList()
Чтобы сделать это с помощью одной команды.
Вы можете определить метрику ошибки для объединения двух линейных сегментов в один, а затем тестирование всех пар сегментов, а затем объединить их, если ошибка ниже определенного порога.
Одним из примеров является этот алгоритм:
- Построить новый сегмент линии x из двух точек, которые далеки друг от друга в двух сегментах линии A и B.
- Найдите минимальное расстояние до x для всех точек в A и B.
- Назначьте ошибку как максимум этих минимальных расстояний.
- Замените A и B на X, если ошибка ниже вашего порога.
Это не лучший алгоритм, но его легко реализовать.
Редактировать 1
Обязательно попробуйте выполнить списки отображения или рендеринг объекта вершины, прежде чем реализовать это.