OpenGL GL выберите или ручное обнаружение столкновения?
Как видно на рисунке
Я рисую набор контуров (полигонов) как GL_LINE_STRIP. Теперь я хочу выбрать кривую (многоугольник) под мышкой,чтобы удалить, переместить..etc в 3D .
Мне интересно, какой метод использовать:
1.используйте сбор и выбор OpenGL. (glRenderMode (GL_SELECT))
2.используйте ручное обнаружение столкновений, используя pick-ray и проверьте, находится ли луч внутри каждого многоугольника.
7 ответов
Я сильно рекомендуем GL_SELECT. Этот метод очень старый и отсутствует в новых версиях GL, и вы, вероятно, получите проблемы с современными видеокартами. Не ожидайте, что он будет поддерживаться оборудованием - вероятно, вы столкнетесь с программным обеспечением (драйвером) для этого режима на многих графических процессорах, если он будет работать вообще. Используйте на свой страх и риск :)
позвольте мне предоставить вам альтернативу.
для твердых, больших объектов, старый, хороший подход выбор:
- включение и установка теста ножниц в окно 1x1 в положении курсора
- рисование экрана без освещения, текстурирования и мультисамплинга, назначение уникального сплошного цвета для каждого "важного" объекта - этот цвет станет идентификатором объекта для выбора
- вызов glReadPixels и получение цвета, который затем будет служить для идентификации выбранного объекта
- очистка буферов, сброс ножниц к нормальному размеру и рисовать сцену нормально.
это дает вам очень надежный метод выбора "на объект". Кроме того, рисование и очистка только 1 пикселя с минимальной операцией на пиксель не повредит вашей производительности, если у вас нет мощности обработки вершин (маловероятно, я думаю) или есть действительно много объектов и, вероятно, будет привязано к процессору по количеству вызовов рисования (но опять же, я считаю, что можно оптимизировать это до одного вызова рисования, Если вы смогл пройти цвет согласно данным по-пиксела).
цвет в RGB составляет 3 байта без знака, но должно быть возможно дополнительно использовать альфа - канал фреймбуфера для последнего байта, поэтому вы получите всего 4 байта-достаточно, чтобы сохранить любой 32-битный указатель на объект в качестве цвета.
кроме того, вы можете создать выделенный объект framebuffer с определенным форматом пикселей (например,GL_R32UI
, или даже GL_RG32UI
Если вам нужно 64 бита) для этого.
выше хорошая и быстрая альтернатива (как с точки зрения надежности, так и во времени реализации) для строгого геометрического подхода.
Я обнаружил, что на новых графических процессорах режим GL_SELECT чрезвычайно медленный. Я играл с несколькими различными способами решения проблемы.
первым было сделать тест столкновения CPU, который работал, но не был так быстро, как мне бы хотелось. Он определенно замедляется, когда вы бросаете лучи на экран (используя gluUnproject), а затем пытаетесь найти, с каким объектом сталкивается мышь. Единственный способ получить удовлетворительные скорости - использовать октри, чтобы уменьшить количество столкновений тесты вниз, а затем сделать тест столкновения ограничивающая коробка-однако, это привело к методу, который не был идеальным пикселей.
метод, на котором я остановился, состоял в том, чтобы сначала найти все объекты под мышью (используя тесты столкновения gluUnproject и bounding box), что обычно очень быстро. Затем я визуализировал каждый из объектов, которые потенциально столкнулись с мышью в backbuffer, как другой цвет. Затем я использовал glReadPixel, чтобы получить цвет под мышью и сопоставить его с объект. glReadPixel-это медленный вызов, так как он должен считываться из буфера кадров. Однако это делается один раз за кадр, что в конечном итоге занимает незначительное количество времени. Вы можете ускорить его, выполнив рендеринг на PBO, если хотите.
Giawa
umanga, не вижу, как ответить inline... может быть, мне стоит зарегистрироваться:)
прежде всего, я должен извиниться за то, что дал вам неправильный Альго - я сделал заднее лицо отбраковки. Но тот, который вам нужен, очень похож, поэтому я запутался... ОУ.
получить положение камеры к вектору мыши, как было сказано ранее.
для каждого контура, петля через все координаты в парах (0-1, 1-2, 2-3, ... n-0) в нем и сделать из них vec, как и раньше. Т. е. прогулка контур.
теперь сделайте кросс-прод этих двух (контур ребра к мыши vec)вместо между парами, как я сказал раньше, сделайте это для всех пар и вектор сложите их все.
в конце найдите величину результирующего вектора. Если результат равен нулю (с учетом ошибок округления), то вне формы, вне зависимости от облицовки. Если вы заинтересованы в облицовке, то вместо mag вы можете сделать эту точку prod с вектором мыши, чтобы найти облицовку и проверьте знак +/ -.
Он работает, потому что algo находит расстояние от векторной линии до каждой точки по очереди. Когда вы суммируете их, и вы находитесь снаружи, тогда все они отменяются, потому что контур закрыт. Если вы внутри, то они все подводят итог. Его на самом деле закон Гаусса электромагнитных полей в физике...
см.: http: / / en.Википедия.org/wiki / Gauss%27s_law и примечание " правая часть уравнения-это общий заряд, заключенный в S, деленный на электрическая константа", отмечая слово "закрытый" - т. е. ноль означает не закрытый.
вы все еще можете сделать эту оптимизацию с ограничивающими рамками для скорости.
в прошлом я использовал GL_SELECT для определения того, какой объект(ы) внес интересующий пиксель(ы), а затем использовал вычислительную геометрию, чтобы получить точное пересечение с объектом(объектами), если это необходимо.
вы ожидаете выбрать, щелкнув контур (на краю) или внутреннюю часть многоугольника? Ваш второй подход звучит так, как будто вы хотите щелкнуть внутри, чтобы выбрать самый плотный полигон. Я так не думаю!--0--> после перевода GL_LINE_STRIP
собирается сделать интерьер реагировать на клики.
Если бы это был истинный контурный график (из изображения я не думаю, что это так, ребра, похоже, пересекаются), тогда был бы доступен гораздо более простой алгоритм.
вы не можете использовать select, если вы остаетесь с линиями, потому что вам придется нажать на пиксели линии, а не пространство внутри линий, ограничивающих их, которые я читаю как то, что вы хотите сделать.
вы можете использовать ответ коса, но для того, чтобы отобразить пространство, вам нужно заполнить его, что потребует преобразования всех ваших контуров в выпуклые типы, что болезненно. Поэтому я думаю, что иногда это сработает и даст неправильный ответ в некоторых случаях, если вы этого не сделаете что.
Что вам нужно сделать, это использовать CPU. У вас есть экстенты представления из окна просмотра и матрицы перспективы. С помощью мыши coord, сгенерировать представление вектора указателя мыши. У вас также есть все координаты контуров.
возьмите первую координату первого контура и сделайте вектор ко второй координате. Сделайте из них вектор. Возьмите 3-й аккорд и сделайте вектор от 2 до 3 и повторите весь путь вокруг вашего контура и, наконец, сделайте последний из coord n снова ноль. Для каждой пары последовательно находим векторное произведение и подвести итоги. Когда у вас есть этот окончательный вектор суммирования, держите его и делайте точечное произведение с вектором направления указателя мыши. Если его +ve, то мышь находится внутри контура, если его-ve, то его нет, и если 0, то я предполагаю, что плоскость контура и направление мыши параллельны.
сделайте это для каждого контура, а затем вы узнаете, какой из них шипами мыши. Его до вас, вы хотите выбрать из этого набора. Самый Высокий Z ?
Это звучит как много работы, но его не так уж плохо и даст правильный ответ. Вы могли бы дополнительно сохранить ограничительные рамки всех ваших контуров, то вы можете в начале те из вектора мыши, делая ту же математику, что и для полного вектора, но только на 4 стороны, и если его не внутри, то контур не может быть либо.