Простой OpenTK Raycasting - PullRequest
       21

Простой OpenTK Raycasting

0 голосов
/ 30 июня 2018

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

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

Отличным примером того, чего я пытаюсь достичь, является система построения, подобная Factorio.

Edit: Сетка - это двумерный массив, который содержит всю информацию о тайле. Плитки в мире - это каждый из 2 треугольников (из массива вершин и индекса). Камера - это перспективная камера (если Factorio использует Orthographic, я мог бы переключиться на нее, если бы она упростила ситуацию).

Редактировать 2: Массив содержит класс с именем TileInformation, который имеет несколько вещей, связанных с тем, что содержится в плитке, и тому подобное. Плитки имеют размер 1x1, а массив - 256x256. (Будет несколько частей сетки, которые могут быть обновлены индивидуально.) Все плитки находятся в сетке с позициями, представленными как int (Система координат является положительной и отрицательной.)

1 Ответ

0 голосов
/ 01 июля 2018

Ваш вопрос все еще недостаточно ясен, но я сделаю несколько предположений и надеюсь, что они соответствуют вашей ситуации.

Во-первых, нам нужен выбирающий луч, который представляет 2D-положение мыши в 3D-пространстве. Для этого мы сначала преобразуем положение мыши из координат пикселей в нормализованные координаты устройства между -1 и 1:

mouseNDCX = 2 * mousePixelX / viewportWidth - 1
mouseNDCY = 1 - 2 * mousePixelY / viewportHeight

Затем мы находим луч. Для этого нам понадобится матрица проекции вида вашей камеры. Тогда:

mouseNear = inverse(viewProjection) * (mouseNDCX, mouseNDCY, 0, 1)
mouseFar  = inverse(viewProjection) * (mouseNDCX, mouseNDCY, 1, 1)

Это даст вам две позиции на луче выбора. Один на плоскости z-ближний и один на плоскости z-дальний. Не забудьте сделать перспективное деление:

mouseNear = (1 / mouseNear.w) * mouseNear
mouseFar = (1 / mouseFar.w) * mouseFar

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

Теперь мы хотим найти пересечение, т. Е .:

          ((1 - t) * mouseNear + t * mouseFar).z = z
<=> mouseNear.z + t * (mouseFar.z - mouseNear.z) = z
<=>                                            t = (z - mouseNear.z) / (mouseFar.z - mouseNear.z)

Это позволяет нам вычислить точку пересечения:

intersection = (1 - t) * mouseNear + t * mouseFar

Эта точка пересечения лежит на плоскости сетки. Наконец, нам нужно найти индекс плитки. Для этого нам нужно только рассмотреть x- и y-компоненты. Если предположить, что источник вашей сетки находится на o, а плитки имеют размер s, то индексы плиток:

i = floor((intersection.x - o.x) / s)
j = floor((intersection.y - o.y) / s)
...