Как сделать рендеринг толстых 2D-линий в виде многоугольников? - PullRequest
21 голосов
/ 26 марта 2009

У меня есть путь, составленный из списка 2D точек. Я хочу превратить их в полосу треугольников, чтобы визуализировать текстурированную линию определенной толщины (и другие подобные вещи). Таким образом, по существу, список двухмерных точек должен стать списком вершин, определяющих контур многоугольника, который при рендеринге будет отображать линию. Проблема заключается в обработке угловых соединений, рукавов, заглушек и т. Д. Полученный полигон должен быть «идеальным» в смысле отсутствия перерисовок, чистых соединений и т. Д., Чтобы его можно было экструдировать или иным образом поиграть.

Существуют ли какие-либо простые ресурсы, которые могут обеспечить понимание алгоритма, код или любую другую информацию об эффективном выполнении этого?

Я абсолютно НЕ хочу полноценную 2D векторную библиотеку (cairo, antigrain, OpenVG и т. Д.) С кривыми, дугами, штрихами и всеми прибамбасами. Я копался в нескольких исходных деревьях для реализаций OpenVG и других вещей, чтобы найти некоторое понимание, но все это ужасно запутано.

Я определенно хочу написать это сам, но есть много вырожденных случаев (маленькие сегменты + толстые ширины + острые углы), которые создают всевозможные проблемы соединения. Даже небольшая помощь спасет меня от попыток разобраться со всеми ними.

РЕДАКТИРОВАТЬ: Вот пример одного из тех вырожденных случаев, которые вызывают уродство, если вы просто переходить от вершины к вершине. Красный - это оригинальный путь. Оранжевые блоки - это прямоугольники, нарисованные с указанной шириной, выровненные по центру на каждом сегменте.

Ответы [ 9 ]

4 голосов
/ 27 марта 2009

Ну да ладно - я пытался решить эту проблему сам. Я потратил два месяца на решение, которое пыталось решить проблему нулевого оверлея. Как вы уже выяснили, вы не можете справиться со всеми вырожденными случаями и одновременно иметь нулевой перерасход.

Однако вы можете использовать гибридный подход:

Напишите себе процедуру, которая проверяет, могут ли соединения быть построены из простой геометрии без проблем. Для этого необходимо проверить угол соединения, ширину линии и длину соединенных отрезков (отрезки, которые короче своей ширины, являются PITA). С некоторой эвристикой вы сможете разобрать все тривиальные случаи.

Я не знаю, как выглядят ваши средние данные строки, но в моем случае более 90% широких линий не имели вырожденных случаев.

Для всех остальных строк:

Скорее всего, вы уже выяснили, что, если вы допускаете перерисовку, генерировать геометрию намного проще. Сделайте это, и пусть алгоритм многоугольника CSG и алгоритм тесселяции сделают тяжелую работу.

Я оценил большинство доступных пакетов тесселяции и в итоге получил тесселятор GLU. Это было быстро, надежно, никогда не ломалось (в отличие от большинства других алгоритмов). Это было бесплатно, и лицензия позволила мне включить его в коммерческую программу. Качество и скорость тесселяции в порядке. Вы не получите качество триангуляции Делоне, но поскольку для рендеринга вам просто нужны треугольники, это не проблема.

Так как я не любил API тесселятора, я поднял код тесселяции из бесплатной эталонной реализации SGI OpenGL, переписал весь интерфейс и добавил пулы памяти, чтобы уменьшить количество выделений. Это заняло два дня, но оно того стоило (например, повышение производительности в пять раз). Решение закончилось коммерческой реализацией OpenVG: -)

Если вы выполняете рендеринг с помощью OpenGL на ПК, вы можете переместить задание тесселяции / CSG из ЦП в графический процессор и использовать приемы stencil-buffer или z-buffer для удаления перерисовки. Это намного проще и может быть даже быстрее, чем тесселяция процессора.

2 голосов
/ 28 октября 2014

Я только что нашел эту удивительную работу:

http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation

Кажется, он делает именно то, что вам нужно, и его лицензия позволяет использовать его даже в коммерческих приложениях. Плюс, автор проделал действительно большую работу, чтобы детализировать свой метод. Вероятно, в какой-то момент я попробую заменить мою собственную, не почти идеальную, реализацию.

2 голосов
/ 27 марта 2009

Простой метод с моей головы.

Делите пополам угол каждой 2-й вершины, это создаст хорошую линию среза. Затем двигайтесь вдоль этой линии, как внутрь, так и наружу, на величину вашей «толщины» (или толщины, деленной на два?), Теперь у вас есть внутренние и внешние точки многоугольника. Перейдите к следующей точке, повторите тот же процесс, создавая новые точки многоугольника по пути. Затем примените триангуляцию, чтобы получить готовые для рендеринга вершины.

1 голос
/ 14 декабря 2011

Мне пришлось испачкать руки и написать небольшой ленточный принтер, чтобы решить похожую проблему.

Для меня проблема заключалась в том, что я хотел, чтобы в OpenGL были жирные линии, у которых не было тех артефактов, которые я видел с OpenGL на iPhone. После рассмотрения различных решений; кривые Безье и тому подобное - я решил, что, вероятно, проще всего сделать свой собственный. Есть несколько разных подходов.

Один из подходов состоит в том, чтобы найти угол пересечения между двумя отрезками, а затем продвинуться вдоль этой линии пересечения на определенное расстояние от поверхности и рассматривать его как вершину ленты. Я попробовал это, и это не выглядело интуитивно; ширина ленты будет варьироваться.

Другой подход заключается в том, чтобы фактически вычислить нормаль к поверхности сегментов линии и использовать ее для вычисления идеального края ленты для этого сегмента и для проведения реальных испытаний на пересечение между сегментами ленты. Это работало хорошо, за исключением того, что для острых углов пересечения сегментов линии ленты были слишком далеко (если угол между сегментами приближался к 180 ').

Я решил проблему острых углов двумя способами. Алгоритм пересечения линии Пола Бурка (который я использовал неоптимизированным способом) предложил определить, находится ли пересечение внутри сегментов. Поскольку оба сегмента идентичны, мне нужно было только проверить один из сегментов на предмет пересечения. Я мог тогда решить, как решить это; Либо, придумав лучшую точку между двумя концами, либо надев концевую заглушку - оба подхода выглядят хорошо - подход с заглушкой может отбросить упорядочение передней / задней поверхности многоугольника для opengl.

См. http://paulbourke.net/geometry/lineline2d/

Смотрите мой исходный код здесь: https://gist.github.com/1474156

0 голосов
/ 13 января 2010

Из вашего изображения выглядит, как будто вы рисуете рамку вокруг линейных сегментов с заливкой и используя оранжевый цвет. Это наверняка приведет к плохим оверлеям. Поэтому первое, что нужно сделать, - это не рендерить черную рамку, а цвет заливки может быть непрозрачным.

Почему вы не можете использовать примитив GL_LINES, чтобы делать то, что вы собираетесь делать? Вы можете указать ширину, фильтрацию, гладкость, текстуру что угодно. Вы можете визуализировать все вершины, используя glDrawArrays (). Я знаю, что это не то, что вы имеете в виду, но, поскольку вы сосредоточены на двухмерном рисовании, это может быть проще. (поиск текстурных линий и т. д.)

0 голосов
/ 11 января 2010

В моем случае я мог позволить себе овердрайт. Я просто рисую круги с радиусом = ширина / 2 с центром в каждой из вершин полилинии.

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

0 голосов
/ 26 марта 2009

Посмотрите, может ли Триангуляция Делоне помочь.

0 голосов
/ 26 марта 2009

Меня это тоже интересует, так как я хочу улучшить рисование дорог в моем картографическом приложении ( Kosmos ). Один из обходных путей, который я использовал, - рисовать ломаную линию дважды, один раз более толстой линией, один раз более тонким, другого цвета. Но на самом деле это не многоугольник, а просто быстрый способ его моделирования. Смотрите некоторые образцы здесь: http://wiki.openstreetmap.org/wiki/Kosmos_Rendering_Help#Rendering_Options

Я не уверен, что это то, что вам нужно.

0 голосов
/ 26 марта 2009

Я думаю, что я бы достиг алгоритма тесселяции. Это правда, что в большинстве случаев, когда они используются, цель состоит в том, чтобы уменьшить количество вершин для оптимизации рендеринга, но в вашем случае вы можете параметризовать, чтобы сохранить все детали - и возможность оптимизации может оказаться полезной.

В Интернете существует множество алгоритмов тесселяции и кода - я несколько лет назад обернул чистый C в DLL для использования с рендерером Delphi для ландшафтов, и они не являются чем-то необычным для продвинутых учебных пособий по кодированию графики и тому подобное.

...