Как реализовать механизмы перемещения, масштабирования и вращения для управления преобразованиями трехмерных объектов?

11

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

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

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

Гримшоу
источник
1
Обычно вы будете направляться в мир с помощью мыши и посмотреть, ударите ли вы гизмо. Вы также можете превратить гизмо в пространство экрана и там обнаруживать столкновения. Обычно, хотя вы просто делаете расстояние от луча до типа отрезка линии. Вращение обычно выполняется как виртуальный трекбол. См. Melax в Gems 1. Программирование игр. Перевод - это в значительной степени точечный продукт, как и масштаб.
RandyGaul

Ответы:

9

В какой-то момент моего времени на e-on я сохранил все тонкости линейки продуктов Vue .
Я могу сказать вам, это займет у вас несколько дней, полный рабочий день.
Если вы не найдете какую-либо библиотеку или супер-умный способ, классический способ - это получить координаты мыши в окне при нажатии, если это относительная координата к области просмотра, вы можете просто разделить x и y на ширину и высоту. получить вектор (float 2d) в диапазоне [0,1]. вычтите (0.5,0.5), чтобы попасть в диапазон [-0.5, 0.5] для x и y.
Затем вы делаете луч из этой координаты, используя x и y просто как луч x и y, и вы устанавливаете z на фокусное расстояние. иногда соотношение сторон является болью в заднице в этой операции. Немного возни и пробная ошибка исправят вас.
Затем вам нужно проверить пересечение с вашими элементами гизмо, либо у вас есть сгенерированная сетка, либо вы смоделировали ее в Blender или другом DCC, либо части сетки, которые могут сочленяться между собой ... Просто используйте эти части сетки как луч / запрос пересечения треугольника.
Или, если у вас есть, луч / цилиндр, луч / сфера в соответствии с вашей внешностью и деталями.
Вы должны иметь подпрограммы пересечения, которые способны применять матрицу преобразования к примитиву, с которым они сталкиваются . Чрезвычайно важно, потому что ваша штуковина будет перемещаться вместе с объектом, которому она движется, она будет вращаться, и она будет масштабироваться с обратным расстоянием до камеры, так что она сохраняет фиксированный проецируемый размер на экране.
Затем у вас есть часть взаимодействия, самая простая - это взять дельту точки, когда мышь была первым событием «мыши вниз», и текущую позицию «перемещения мыши» в чистом 2D, и использовать эту дельту в качестве текущего движения оси в мировом пространстве, умноженном на некоторые, kкоторые вы решите эмпирически. В соответствии с вашими внутренними единицами в зависимости от пикселя в сравнении с текущим масштабом увеличения и т. Д.
Последний шаг - просто применить матрицу гизмо к манипулируемому объекту, чтобы он следовал за ним.

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

Я предлагаю вам скачать Embree 2.0 от Intel, чтобы выполнить запрос пересечения лучей и треугольников, так что вам не нужно беспокоиться о его кодировании. Или вы можете безжалостно копировать / вставлять и адаптировать код из Blender ... Я думаю, что они перешли на лицензию Apache? Должно быть возможно по закону.

v.oddou
источник
1
Большое спасибо за ответ. Это действительно полезно. Я знал, что не сошел с ума, когда чувствовал себя подавленным, казалось бы, легкой задачей. Я недооцениваю его сложность и в конечном итоге застрял на одной и той же проблеме в течение нескольких дней. В следующий раз, когда я пойду и справлюсь с этим, я обязательно составлю хороший план. Спасибо
Гримшоу
0

Для манипулятора-переводчика я использую следующий алгоритм:

1) Когда мышь нажата, нам нужно проверить, пересекает ли луч стрелку. Например, мы рассмотрим стрелку X Мы строим Луч в мировом пространстве (основываясь на усечённости камеры и положении мыши). Построим плоскость, в которой лежит ось x: ее нормаль равна V, крест X пересекает V, где V - вектор от центра к камере, X - ось x. Затем мы пересекаем луч с плоскостью и поэтому находим точку пересечения в мировых координатах. Затем мы проецируем сегмент оси x и полученную точку обратно на экран, находим расстояние между проецируемым сегментом и проецируемой точкой на экране. если оно меньше нескольких пикселей, мышь пересекает ось. Также мы вычисляем вектор дельты мирового пространства между центром выделения и нашим пересечением.

Эту процедуру мы делаем для 3-х осей, поэтому находим расстояния до всех осей. Найдите минимальное расстояние. Итак, мы нашли, по какой оси пересекается мышь.

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

толчок рор
источник