Как визуализировать алгоритмы случайного распределения в Swift и ARKit

1656549026 kak vizualizirovat algoritmy sluchajnogo raspredeleniya v swift i arkit

Дена Вышинского

1*kwVxwULlpFSCfMpkzQhVvg
https://xkcd.com/221/

Дерево в лесу

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

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

Далее, мы знаем, что встроенные генераторы случайных данных не очень случайны, если не принять особые меры предосторожности.

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

Существует несколько способов осуществить случайное равное распределение. Как любой достойный разработчика, я нашел пару, которые имеют простые реализации, которые хорошо работают для нашей цели. Давайте рассмотрим каждый из них и реализуем их в Swift с помощью ARKit и SceneKit.

Бросьте им кубики!

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

Давайте создадим нашу программу и разберем некоторые основные вещи. Откройте Xcode и создайте новый проект с помощью шаблона приложения дополненной реальности. Создайте и запустите приложение, чтобы убедиться, что все работает, и вы видите, что корабль по умолчанию появляется перед телефоном при запуске приложения.

Дальше мы собираемся настроить наш проект, как это делали для первого учебника из моей серии ARKit. Выполните шаги в этом учебнике с одной разницей в имени файла сцены. Вместо того чтобы назвать это HoverSceneмы назовем это MainScene вместо этого. Добавьте делегат визуализации, как описано в учебнике, и следуйте Дополнительные кредиты раздел, где создается распознавание жестов прикосновения.

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

Создайте файл под названием PointGenerator.swift. Здесь мы поместим несколько итераций наших алгоритмов. Начнём с генератора точек случайных чисел. Мы создадим протокол, который будут соблюдать наши алгоритмы, что облегчит переключение между алгоритмами в нашем источнике позже.

Наш протокол прост. Учитывая количество точек для создания, а также ширину и длину для ограничения точек, верните массив точек:

Наши RandomPointGenerator будет следовать этому классу и выведет наш первый набор результатов:

Код здесь простой. Мы выполняем итерации и создаем точки, лежащие в пределах ширины и длины, размещая точки с обеих сторон от середины этих ограничений. Мы добавляем созданные точки в массив, а затем просто возвращаем точки.

Создайте класс под названием Visualizer происходит из SCNNode. Этот класс будет служить контейнером, содержащим объекты, которые мы разместим в мире для визуализации набора точек. Сейчас мы собираемся создавать маленькие сферы в каждой точке, сгенерированные нашими алгоритмами.

Вот как должен выглядеть наш класс:

Ладно, теперь мы готовы создать наши точки. Вернемся к нашему MainScene класс и добавьте метод с ним createPointFieldпринимающий а SCNVector3 позиция:

Мы собираемся позвонить это из нашего ViewController когда мы касаемся экрана. Идем к нашим didTapScreen метод и сделайте часть, где мы раньше создали сферу (в первом учебнике), выглядеть так:

Создайте и запустите и теперь мы реализовали наш первый алгоритм.

1*Q7WoWRzhOP9iSMBkKDVofA
Случайное размещение очков. Не замечательно.

Обратите внимание на то, как сферы группируются в определенных местах. Именно этого мы хотим избежать.

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

Пуассонова выборка и лучший кандидат Митчелла

В качестве альтернативы способу генератора случайных чисел нам нужен алгоритм, возвращающий набор точек, близких друг к другу, но не ближе некоторого заданного минимального расстояния. Вот где Диск Пуассона входит в картину. Существует несколько методов реализации метода Пуассона-диска. Тот, который мы собираемся реализовать в нашем коде, называется Лучший кандидат Митчелла алгоритм. Это легко реализовать и быстро работает.

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

Для реализации мы собираемся создать другую реализацию нашего PointGenerator протокол:

Вернемся к нашему MainScene класса, прокомментируйте строки случайного генератора и добавьте эти новые строки в:

Запустите приложение еще раз, и давайте посмотрим на наши результаты.

1*7xvbJ3FRTKwiEPdCKmPhWQ
Диск Пуассона с использованием метода лучшего кандидата Митчелла

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

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

Алгоритм семян подсолнечника

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

Вернемся к нашему PointGenerator файл и создайте нашу новую реализацию:

Здесь вы заметите, что мы игнорируем ширина и высота переданы параметры. Это потому, что вместо того, чтобы ограничивать точки по области, мы будем равномерно распределять точки по спирали, пока не закончатся точки.

Смена alpha в параметре, переданном в sunflower способ контролирует зернистость точек на краю границы. То есть мы можем сделать предел более гладким или грубым, управляя распределением точек. Приведенный выше код использует an alpha с 2что находится на высокой стороне, что приводит к более ровному пределу.

Идем к нашим MainScene снова и прокомментируйте предыдущий алгоритм. Давайте добавим звонок, чтобы получить наш Sunflower точки генерации шаблонов:

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

1*jfw0td6NYTbk0m9m637FJQ
Алгоритм подсолнечника

Как видите, у нас есть узор, имитирующий то, как подсолнечники держат семена. Существует также интересный вариант, который мы можем применить к алгоритму, как подробно описано в одном из комментариев по этому вопросу о переполнении стека.

Меняя theta к пеленгу комментатор превратил алгоритм в геодезическое образование.

Изменить theta строка в нашем коде к следующему:

Давайте снова запустим наш алгоритм и посмотрим, как он выглядит.

1*DLjYdq6QI0HUu4SRVC90Mw
Алгоритм подсолнечника со спиральным узором

Круто! Теперь у нас есть узор в виде спиралей.

Говоря о спирали, давайте проверим последний алгоритм.

Спираль Фогеля

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

Давайте введем его, а затем настроим его, чтобы увидеть, как это повлияет на результаты.

В нашем PointGenerator класса, добавьте нашу реализацию этого метода.

Этот алгоритм, как и алгоритм семян подсолнечника, также игнорирует ширина и высота параметры

Давайте заменим предыдущий алгоритм на новые вызовы.

Давайте попробуем и посмотрим, что мы получим.

1*E8jaDtxL84_HPeJVAmXu3w
Спираль Фогеля

Хорошо! Теперь давайте попробуем разные вариации этого алгоритма. Изменяя формулу, мы можем получить разные спиральные образования. Изменить it декларацию к следующей строке:

Запустите это и проверьте, что мы получаем.

1*QAo1ria723ab_6VSTUTgVg
Спираль Фогеля, похожая на подсолнечник

Эта спираль теперь выглядит как перевернутая версия нашей спирали «Подсолнух» с обновлением theta. Любопытно!

Давайте попробуем с помощью такой формулы:

1*uBr1Oa3mrnt3GmdxCiWg5g
Спирали Фогеля

Подобен первому алгоритму, но спирали разделены. Очень классная вещь!

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

Это не была бы моя статья, если бы мы не сделали что-то крутое из того, что мы только что узнали, не правда ли?

Загрузите некоторые модели деревьев из 3D-моделей, например Sketchfab или Turbosquid. При необходимости конвертируйте их в формат Collada (DAE) и добавьте к своему проекту. Возможно, вам потребуется изменить их размер, чтобы получить надлежащий масштаб при размещении их в своей сцене, но вы узнаете, когда начнете использовать их. Обязательно используйте низкополигонную модель, поскольку мы говорим о создании десятков и даже сотен экземпляров объектов.

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

Вот что мое Tree класс выглядит так:

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

В нашем Visualizer код, давайте изменим наш Tree создание, чтобы немного анимировать зум.

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

Строй и бегай, и теперь у нас есть счастливый маленький лес, созданный почти без труда.

1*3xGOTLUtmoisLbHm-CO2ag
Наш счастливый лесок

Надеюсь, вам понравился этот маленький опыт. Не стесняйтесь показать свою работу в разделе комментариев!

Даниэль Вышинский – разработчик, работавший на большем количестве платформ и языков, чем он хочет признавать. Он верит в создание продуктов, создающих незабываемые впечатления для пользователей. Для Дэна пользователи на первом месте, платформы на втором месте. Подписывайтесь на Дэна на Medium или Twitter, чтобы узнать больше от него. Также посмотрите блог s23NYC: Engineering, где публикуется много замечательного контента от команды Nike Digital Innovation.

Примечание автора: взгляды мои и не обязательно представляют взгляды моего работодателя

Добавить комментарий

Ваш адрес email не будет опубликован.