OpenGL GL_SELECT или ручное обнаружение столкновения?

Как видно на рисунке

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

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

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

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

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

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

Giawa

Ответ 3

umanga, Cant посмотреть, как ответить inline... может быть, я должен зарегистрироваться:)

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

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

Первое легко реализовать и широко использовать.