Я разрабатываю игру с Minecraft-подобным ландшафтом, сделанным из блоков. Поскольку базовый рендеринг и загрузка фрагментов уже сделаны, я хочу реализовать выбор блоков.
Поэтому мне нужно выяснить, к какому блоку относится камера от первого лица. Я уже слышал о том, чтобы не спроектировать всю сцену, но я решил не делать этого, потому что это звучит глупо и не точно. Может быть, я мог бы как-то навести луч в направлении обзора, но я не знаю, как проверить столкновение с блоком в моих данных вокселей. Конечно, эти вычисления должны выполняться на процессоре, так как мне нужны результаты для выполнения логических операций игры.
Итак, как я могу узнать, какой блок перед камерой? Если это предпочтительнее, как я могу навести луч и проверить столкновения?
источник
Ответы:
Когда у меня возникла эта проблема во время работы над моими кубами , я обнаружил статью «Быстрый алгоритм обхода вокселей для трассировки лучей» Джона Аманатида и Эндрю Ву, 1987 г., в которой описывается алгоритм, который можно применить к этой задаче; он точен и требует только одной итерации цикла на пересеченный воксель.
Я написал реализацию соответствующих частей алгоритма статьи на JavaScript. Моя реализация добавляет две функции: она позволяет указать ограничение на расстояние лучевой трансляции (полезно для избежания проблем с производительностью, а также для определения ограниченного «охвата»), а также вычисляет, какая грань каждого вокселя введена лучом.
Входной
origin
вектор должен быть масштабирован таким образом, чтобы длина стороны вокселя была равна 1. Длинаdirection
вектора не является существенной, но может повлиять на числовую точность алгоритма.Алгоритм работает с использованием параметризованного представления луча
origin + t * direction
. Для каждой оси координат, мы продолжаем отслеживатьt
значение , которое мы имели бы , если бы мы сделали шаг достаточного , чтобы пересечь границу вокселей вдоль этой оси (то есть изменение целой части координат) в переменныхtMaxX
,tMaxY
иtMaxZ
. Затем, мы делаем шаг (используяstep
иtDelta
переменные) , вдоль какой оси имеет наименьшееtMax
- то есть в зависимости от того вокселей-граница ближе.Постоянная ссылка на эту версию источника на GitHub .
источник
function intbounds(s,ds) { return (ds > 0? Math.ceil(s)-s: s-Math.floor(s)) / Math.abs(ds); }
. ПосколькуInfinity
оно больше всех чисел, я не думаю, что вам нужно защищаться от того, чтобы ds был там 0.1/ds
вызывает увеличение одной из других осей. Исправление состоит в том, чтобы написать,intfloor
чтобы проверить, является ли обаds
отрицательным иs
является целочисленным значением (mod возвращает 0), и возвращает 0.0 в этом случаеВозможно, обратите внимание на линейный алгоритм Брезенхэма , особенно если вы работаете с юнит-блоками (как это обычно бывает в большинстве игр Minecraftish).
В основном это берет любые две точки и прослеживает непрерывную линию между ними. Если вы разыгрываете вектор от игрока до его максимального расстояния выбора, вы можете использовать это, и игроки позиционируются как очки.
У меня есть 3D-реализация в Python здесь: bresenham3d.py .
источник
Чтобы найти первый блок перед камерой, создайте цикл for, который проходит от 0 до некоторого максимального расстояния. Затем умножьте передний вектор камеры на счетчик и проверьте, является ли блок в этой позиции сплошным. Если это так, сохраните положение блока для последующего использования и прекратите цикл.
Если вы также хотите иметь возможность размещать блоки, выбор лица не сложнее. Просто вернитесь назад от блока и найдите первый пустой блок.
источник
Я сделал сообщение о Reddit с моей реализацией , в которой используется алгоритм Брезенхема. Вот пример того, как вы бы это использовали:
Вот сама реализация:
источник