OpenGL GL_SELECT или ручное обнаружение столкновений? - PullRequest
10 голосов
/ 28 октября 2010

Как видно на изображении

http://oi56.tinypic.com/ifu33k.jpg

Я рисую набор контуров (многоугольников) как GL_LINE_STRIP.Теперь я хочу выбрать кривую (многоугольник) под мышью, чтобы удалить, переместить ... и т. Д. В 3D.

Мне интересно, какой метод использовать:

1.Использовать выбор и выбор OpenGL.(glRenderMode (GL_SELECT))

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

Ответы [ 7 ]

16 голосов
/ 30 октября 2010

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

Позвольте мне предоставить вам альтернативу.

Для твердых, больших объектов, есть старый, хороший подход выбора:

  • Включение и установка теста ножниц для окна 1x1 в позиции курсора
  • рисование экрана без освещения, текстурирования и мультисэмплинга, назначение уникального сплошного цвета для каждого "важного" объекта - этот цвет станетИдентификатор объекта для выбора
  • вызова glReadPixels и получения цвета, который затем будет использоваться для идентификации выбранного объекта
  • очистки буферов, сброса ножниц до нормального размера и обычного рисования сцены.

Это дает вам очень надежный метод выбора для каждого объекта.Кроме того, отрисовка и очистка только 1 пикселя с минимальной обработкой на пиксель не сильно скажется на вашей производительности, если только у вас недостаточно вычислительной мощности вершин (я думаю, это маловероятно) или у вас действительно много объектов и вы, вероятно, получите ЦП.ограничено числом вызовов отрисовки (но, опять же, я считаю, что можно оптимизировать это до одного вызова отрисовки, если вы можете передать цвет в виде данных на пиксель).

Цвет в RGB равен 3байты без знака, но должна быть возможность дополнительно использовать альфа-канал кадрового буфера для последнего байта, так что вы получите всего 4 байта - достаточно для хранения любого 32-битного указателя на объект в качестве цвета.

В качестве альтернативы, вы можете создать для этого выделенный объект кадрового буфера с определенным форматом пикселей (например, GL_R32UI или даже GL_RG32UI, если вам нужно 64 бита).

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

5 голосов
/ 31 октября 2010

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

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

Метод, на котором я остановился, состоял в том, чтобы сначала найти все объекты под мышью (используя gluUnproject и тесты столкновений ограничивающего прямоугольника), что обычно очень быстро. Затем я рендерил каждый из объектов, которые потенциально сталкивались с мышью в буферном буфере, другим цветом. Затем я использовал glReadPixel, чтобы получить цвет под мышью и отобразить его обратно на объект. glReadPixel - медленный вызов, так как он должен читать из буфера кадра. Однако это делается один раз за кадр, что в итоге занимает незначительное количество времени. Вы можете ускорить его, рендеринг в PBO, если хотите.

Giawa

3 голосов
/ 01 ноября 2010

уманга, не могу посмотреть, как ответить в строке ... может мне стоит зарегистрироваться:)

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

Получите положение камеры к вектору мыши, как сказано выше.

Для каждого контура переберите в нем все координаты попарно (0-1, 1-2, 2-3, ... n-0) и сделайте из них вектор, как и раньше. То есть пройти по контуру.

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

В конце найдите величину результирующего вектора. Если результат равен нулю (с учетом ошибок округления), то вы вне фигуры - независимо от облицовки. Если вы заинтересованы в обращении к лицу, то вместо магнита вы можете сделать это с помощью точки мыши с вектором мыши, чтобы найти лицо и проверить знак + / -.

Это работает, потому что алгоритм находит величину расстояния от векторной линии до каждой точки по очереди. Когда вы суммируете их, и вы находитесь снаружи, то все они отменяются, потому что контур замкнут. Если вы внутри, то все они подводят итоги. Это на самом деле закон Гаусса электромагнитных полей в физике ...

См .: http://en.wikipedia.org/wiki/Gauss%27s_law и отметьте, что "правая часть уравнения - это суммарный заряд, заключенный в S, деленный на электрическую постоянную", отмечая слово "вложенный" - то есть ноль означает не заключенный.

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

1 голос
/ 31 октября 2010

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

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

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

Возьмите первую координату первого контура и сделайте вектор второй координатой. Сделайте из них вектор. Возьмите 3-ю координату и сделайте вектор от 2 до 3, повторите все вокруг вашего контура и, наконец, сделайте последний из координат n обратно в 0 снова. Для каждой пары в последовательности найдите перекрестное произведение и суммируйте все результаты. Когда у вас есть этот окончательный вектор суммирования, держите его и делайте точечное произведение с вектором направления указателя мыши. Если его + ve, то мышь находится внутри контура, если -ve, то его нет, а если 0, то я предполагаю, что плоскость контура и направление мыши параллельны.

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

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

1 голос
/ 30 октября 2010

Ожидаете ли вы выбрать, щелкнув контур (на краю) или внутреннюю часть многоугольника? Ваш второй подход звучит так, как будто вы хотите, чтобы щелчки в интерьере выбирали самый плотный, содержащий многоугольник. Я не думаю, что GL_SELECT после рендеринга GL_LINE_STRIP заставит интерьер реагировать на щелчки.

Если бы это был настоящий контурный график (из изображения, которое я не думаю, ребра пересекаются), то был бы доступен гораздо более простой алгоритм.

1 голос
/ 28 октября 2010

В прошлом я использовал GL_SELECT, чтобы определить, какой объект (ы) предоставил интересующий пиксель (пиксели), а затем использовал вычислительную геометрию, чтобы получить точное пересечение с объектом (ами), если требуется.

0 голосов
/ 28 октября 2010

Первый прост в реализации и широко используется.

...